From 2016d5b3a595358532056cc8ed1dfd8e5cb88e29 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 15 Jan 2026 17:36:23 -0700 Subject: [PATCH 1/2] Reset CMOS using Intel PMC RTC_PWR_STS if supported --- src/app/bios.rs | 34 +++++++++++++++++++++++++++++----- src/app/ec.rs | 8 ++++---- src/app/intel_pmc.rs | 33 +++++++++++++++++++++++++++++++++ src/app/mod.rs | 1 + 4 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 src/app/intel_pmc.rs diff --git a/src/app/bios.rs b/src/app/bios.rs index bfc61f6..9b7f46f 100644 --- a/src/app/bios.rs +++ b/src/app/bios.rs @@ -16,7 +16,7 @@ use std::vars::{get_boot_item, get_boot_order, set_boot_item, set_boot_order}; use super::{ Component, FIRMWARECAP, FIRMWAREDIR, FIRMWARENSH, FIRMWAREROM, H2OFFT, IFLASHV, UEFIFLASH, - UefiMapper, cmos, pci_mcfg, shell, + UefiMapper, cmos, intel_pmc, pci_mcfg, pci_read, shell }; fn copy_region( @@ -490,10 +490,34 @@ impl Component for BiosComponent { println!(); } - // Have coreboot reset the option table to the defaults. - let mut cmos_options = cmos::CmosOptionTable::new(); - unsafe { - cmos_options.invalidate_checksum(); + // Check the SPI PCI ID to identify the platform + let intel_pmc_opt = match pci_read(0x00, 0x1f, 0x5, 0x00).unwrap_or(0) { + 0x43A4_8086 | // Tiger Lake-H + 0x51A4_8086 | // Alder Lake-P + 0x7723_8086 | // Arrow Lake-HU + 0x7A24_8086 | // Alder Lake-S + 0x7E23_8086 | // Meteor Lake-HU + 0xA0A4_8086 // Tiger Lake + => { + // TigerLake and onwards have used the same register settings + Some(intel_pmc::IntelPmc::tigerlake()) + }, + _ => None, + }; + match intel_pmc_opt { + Some(intel_pmc) => { + unsafe { + // Setting RTC_PWR_STS will trigger a CMOS reset on any firmware, coreboot or proprietary + intel_pmc.set_rtc_pwr_sts(); + } + } + None => { + let mut cmos_options = cmos::CmosOptionTable::new(); + unsafe { + // Invalidating checksum will trigger a CMOS reset only on coreboot + cmos_options.invalidate_checksum(); + } + } } } else { find(FIRMWARENSH)?; diff --git a/src/app/ec.rs b/src/app/ec.rs index 569aba2..996615d 100644 --- a/src/app/ec.rs +++ b/src/app/ec.rs @@ -261,7 +261,7 @@ impl EcComponent { "NH5xHX" => "system76/gaze16-3050".to_string(), "NH5_7HPQ" => { // If the builtin ethernet at 00:1f.6 is present, this is a -b variant - if pci_read(0x00, 0x1f, 0x6, 0x00).unwrap() == 0x15fa8086 { + if pci_read(0x00, 0x1f, 0x6, 0x00).unwrap() == 0x15fa_8086 { "system76/gaze16-3060-b".to_string() } else { "system76/gaze16-3060".to_string() @@ -271,7 +271,7 @@ impl EcComponent { "NPxxPNP" => { // If the builtin ethernet at 00:1f.6 is present, this is a -b variant let pciid = pci_read(0x00, 0x1f, 0x6, 0x00).unwrap(); - if pciid == 0x1a1e8086 || pciid == 0x1a1f8086 { + if pciid == 0x1a1e_8086 || pciid == 0x1a1f_8086 { "system76/gaze17-3060-b".to_string() } else { "system76/gaze17-3060".to_string() @@ -287,7 +287,7 @@ impl EcComponent { // Check SPI device at 1f.5 for Arrow Lake or Meteor Lake match pci_read(0x00, 0x1f, 0x5, 0x00).unwrap() { // 0x7723 is Arrow Lake (darp11) - 0x77238086 => { + 0x7723_8086 => { // If GPP_E2 is high, this is the 16 inch variant unsafe { let sideband = Sideband::new(0xE000_0000); @@ -299,7 +299,7 @@ impl EcComponent { } }, // 0x7e23 is Meteor Lake (darp10) - 0x7e238086 => { + 0x7e23_8086 => { // If GPP_E2 is high, this is the 16 inch variant unsafe { let sideband = Sideband::new(0xE000_0000); diff --git a/src/app/intel_pmc.rs b/src/app/intel_pmc.rs new file mode 100644 index 0000000..2d204da --- /dev/null +++ b/src/app/intel_pmc.rs @@ -0,0 +1,33 @@ +pub struct IntelPmc { + pwrmbase: usize, + gen_pmcon_b_offset: usize, + gen_pmcon_b_rtc_pwr_sts: u32, +} + +impl IntelPmc { + pub fn tigerlake() -> Self { + Self { + //TODO: read from PCI 00:1f.2 BAR? This device is hidden + // so that may not work. + pwrmbase: 0xfe000000, + gen_pmcon_b_offset: 0x1024, + gen_pmcon_b_rtc_pwr_sts: 1 << 2, + } + } + + unsafe fn read(&self, offset: usize) -> u32 { + let ptr = (self.pwrmbase + offset) as *const u32; + unsafe { ptr.read_volatile() } + } + + unsafe fn write(&self, offset: usize, value: u32) { + let ptr = (self.pwrmbase + offset) as *mut u32; + unsafe { ptr.write_volatile(value) } + } + + pub unsafe fn set_rtc_pwr_sts(&self) { + let mut value = unsafe { self.read(self.gen_pmcon_b_offset) }; + value |= self.gen_pmcon_b_rtc_pwr_sts; + unsafe { self.write(self.gen_pmcon_b_offset, value); } + } +} \ No newline at end of file diff --git a/src/app/mod.rs b/src/app/mod.rs index b9a8924..d6775f7 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -28,6 +28,7 @@ mod bios; mod cmos; mod component; mod ec; +mod intel_pmc; mod mapper; mod pci; mod sideband; From 4255804be30f93e1f3e65b00bdbce4736ef178c2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 15 Jan 2026 17:39:11 -0700 Subject: [PATCH 2/2] Remove resolved TODO --- src/app/intel_pmc.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/intel_pmc.rs b/src/app/intel_pmc.rs index 2d204da..5ebdb0f 100644 --- a/src/app/intel_pmc.rs +++ b/src/app/intel_pmc.rs @@ -7,8 +7,6 @@ pub struct IntelPmc { impl IntelPmc { pub fn tigerlake() -> Self { Self { - //TODO: read from PCI 00:1f.2 BAR? This device is hidden - // so that may not work. pwrmbase: 0xfe000000, gen_pmcon_b_offset: 0x1024, gen_pmcon_b_rtc_pwr_sts: 1 << 2,