Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable CSME by CMOS option on meer9 before flashing #124

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions src/app/bios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,10 @@ impl Component for BiosComponent {

fn validate(&self) -> Result<bool> {
let data = load(self.path())?;

if let Some((mut spi, _hsfsts_ctl)) = self.spi() {
// if hsfsts_ctl.contains(HsfStsCtl::FDOPSS) {
// println!("SPI currently locked, attempting to unlock");
// println!("\nSPI currently locked, attempting to unlock");
// Self::spi_unlock();
// }

Expand Down Expand Up @@ -484,12 +485,9 @@ impl Component for BiosComponent {
println!();
}

// Invalidate the 2-byte CMOS checksum to force writing the option defaults.
let mut cmos = cmos::Cmos::default();
let old_hi = cmos.read(123);
let old_lo = cmos.read(124);
cmos.write(123, !old_hi);
cmos.write(124, !old_lo);
// Have coreboot reset the option table to the defaults.
let mut cmos_options = cmos::CmosOptionTable::new();
unsafe { cmos_options.invalidate_checksum(); }
} else {
find(FIRMWARENSH)?;

Expand Down
76 changes: 75 additions & 1 deletion src/app/cmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub struct Cmos {
}

impl Cmos {
pub const PORT_BANK0: u16 = 0x70;

pub fn new(port: u16) -> Self {
Self {
port: Pio::<u8>::new(port),
Expand All @@ -28,6 +30,78 @@ impl Cmos {

impl Default for Cmos {
fn default() -> Self {
Self::new(0x70)
Self::new(Self::PORT_BANK0)
}
}

// HACK: All boards use the same option table layout, so hard-code the logic
// so we can get meer9 working.

pub struct CmosOptionTable {
cmos: Cmos,
}

impl CmosOptionTable {
/// Offset into CMOS RAM of the table `check_sum`: Bit 984
const CHECKSUM_OFFSET: u8 = (984 / 8) as u8;
/// Offset into CMOS RAM of the option `me_state`: Bit 416
const ME_STATE_OFFSET: u8 = (416 / 8) as u8;

pub fn new() -> Self {
Self {
cmos: Cmos::default(),
}
}

/// Read the checksum from the CMOS option table.
pub fn checksum(&mut self) -> u16 {
let hi = u16::from(self.cmos.read(Self::CHECKSUM_OFFSET));
let lo = u16::from(self.cmos.read(Self::CHECKSUM_OFFSET + 1));

hi << 8 | lo
}

/// Write the checksum to the CMOS option table.
pub unsafe fn set_checksum(&mut self, cksum: u16) {
let hi = (cksum >> 8) as u8;
let lo = cksum as u8;

self.cmos.write(Self::CHECKSUM_OFFSET, hi);
self.cmos.write(Self::CHECKSUM_OFFSET + 1, lo);
}

// Get CSME state in CMOS option table.
pub fn me_state(&mut self) -> bool {
let state = self.cmos.read(Self::ME_STATE_OFFSET);

// me_state
// 0: Enable
// 1: Disable
state & 0x01 == 0x00
}

/// Set CSME state via CMOS option table.
pub unsafe fn set_me_state(&mut self, state: bool) {
let old_state = self.cmos.read(Self::ME_STATE_OFFSET);
let old_cksum = self.checksum();

// me_state
// 0: Enable
// 1: Disable
let (new_state, new_cksum) = if state {
(old_state & 0xFE, old_cksum - 1)
} else {
(old_state | 0x01, old_cksum + 1)
};

self.cmos.write(Self::ME_STATE_OFFSET, new_state);
self.set_checksum(new_cksum);
}

/// Invalidate the 2-byte CMOS checksum to have coreboot erase the option
/// table and write out the defaults.
pub unsafe fn invalidate_checksum(&mut self) {
let cksum = self.checksum();
self.set_checksum(!cksum);
}
}
28 changes: 28 additions & 0 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,34 @@ fn inner() -> Result<()> {
if c == '\n' || c == '\r' {
success = true;

for c in &components {
if c.model() == "meer9" {
// HACK:
// CSME must be disabled or in read-only mode to write
// CSME region of SPI flash. PCH reset does not trigger
// CSME reset, so ME_OVERRIDE will not be in effect on
// cold reset. HECI reset can't be requested after End
// Of Post (before payload runs), so disable CSME as a
// workaround.
let mut cmos_options = cmos::CmosOptionTable::new();
// XXX: Probably better to check for HECI device.
if cmos_options.me_state() {
println!("Disabling CSME for writing SPI flash");
unsafe { cmos_options.set_me_state(false); }

println!("System will reboot in 5 seconds");
let _ = (std::system_table().BootServices.Stall)(5_000_000);

(std::system_table().RuntimeServices.ResetSystem)(
ResetType::Cold,
Status(0),
0,
ptr::null(),
);
}
}
}

{
let ec_kind = unsafe { EcKind::new(true) };
// If EC tag does not exist, unlock the firmware
Expand Down
Loading