Skip to content

Commit

Permalink
Disable CSME by CMOS option on meer9 before flashing
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Crawford <tcrawford@system76.com>
  • Loading branch information
crawfxrd committed Dec 6, 2024
1 parent 826fb72 commit 332f0d2
Showing 2 changed files with 106 additions and 8 deletions.
38 changes: 31 additions & 7 deletions src/app/bios.rs
Original file line number Diff line number Diff line change
@@ -217,9 +217,36 @@ impl Component for BiosComponent {

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

if self.system_version.as_str() == "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!("\nDisabling 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(),
);
}
}

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();
// }

@@ -484,12 +511,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)?;

76 changes: 75 additions & 1 deletion src/app/cmos.rs
Original file line number Diff line number Diff line change
@@ -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),
@@ -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);
}
}

0 comments on commit 332f0d2

Please sign in to comment.