From 77a6782e671df2863770b3a2c2e5326e3bd0eddf Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Thu, 16 Oct 2025 15:32:21 +0200 Subject: [PATCH 1/2] ifd: add more references and notes Signed-off-by: Daniel Maslowski --- src/ifd.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ifd.rs b/src/ifd.rs index 1db2bb2..e77eeb5 100644 --- a/src/ifd.rs +++ b/src/ifd.rs @@ -2,13 +2,20 @@ //! //! The IFD was extended over time; for reference, //! see +//! and +//! and +//! and //! and //! and //! and //! and coreboot `util/ifdtool/`. //! -//! The IFD consists of multiple sections, which got more over generations -//! of processors. The following table is based on the Chip 600 PCH docs. +//! The IFD consists of multiple fields and sections, which got more over generations +//! of processors. Some semantics also changed over time. +//! Unfortunately, there is no clear single source of truth documenting which +//! processors would require which exact fields, either. One major change came with +//! Skylake, as per coreboot commit `1f7fd720c81755144423f2d4062c39cc651adc0a`. +//! The following table is based on the 600 series chipset PCH datasheet. //! Offsets of specific sections are described via the Descriptor Map, //! called base addresses, commonly abbreviation as xxBA. //! NOTE: The base addresses are compact values and really mean bits 4..11 @@ -26,6 +33,10 @@ //! | Management Engine VSCC Table | //! | Descriptor Upper Map | //! | OEM Section | +//! +//! For a list of acronyms, see the Serial Peripheral Interface (SPI) section +//! in the 400 or 600 series chipset PCH datasheet volume 1. +//! // We retain the all-uppercase acronyms in the struct definitions. // Lowercase helpers are provided through implementations. From a0506c12b5bcdf31e93b606947aba43aae5011e8 Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Thu, 16 Oct 2025 15:34:00 +0200 Subject: [PATCH 2/2] ifd: add straps and helpers for known bits Signed-off-by: Daniel Maslowski --- src/ifd.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/src/ifd.rs b/src/ifd.rs index e77eeb5..15cfdc3 100644 --- a/src/ifd.rs +++ b/src/ifd.rs @@ -42,11 +42,11 @@ // Lowercase helpers are provided through implementations. #![allow(non_snake_case)] -use std::fmt::Display; +use std::fmt::{Debug, Display}; use bitfield_struct::bitfield; use serde::{Deserialize, Serialize}; -use zerocopy::FromBytes; +use zerocopy::{FromBytes, Ref}; use zerocopy_derive::{FromBytes, Immutable, IntoBytes}; // NOTE: This is the LE representation. @@ -89,8 +89,8 @@ impl Display for FLMAP0 { let nc = self.nc(); let frba = self.frba(); let nr = self.nr(); - let c = format!(" components: {nc}, base: 0x{fcba:08x}"); - let r = format!(" regions: {nr}, base: 0x{frba:08x}"); + let c = format!(" components: {nc}, base: 0x{fcba:08x}"); + let r = format!(" regions: {nr}, base: 0x{frba:08x}"); write!(f, "{c}\n{r}") } } @@ -130,9 +130,9 @@ impl Display for FLMAP1 { // NOTE: On later platforms, FISBA was changed into FPSBA (PCH Strap). let fisba = self.fisba(); let isl = self.isl(); - let m = format!(" masters: {nm}, base: 0x{fmba:08x}"); - let i = format!(" ICH8 strap length: {isl}, base: 0x{fisba:08x}"); - write!(f, "{m}\n{i}") + let m = format!(" masters: {nm}, base: 0x{fmba:08x}"); + let s = format!(" ICH8/PCH straps: {isl:2}, base: 0x{fisba:08x}"); + write!(f, "{m}\n{s}") } } @@ -153,11 +153,13 @@ impl FLMAP2 { } } +// Only for 100 up to 900 series chipset PCHs, per coreboot util/ifdtool impl Display for FLMAP2 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let fmsba = self.fmsba(); + // coreboot calls this PSL let msl = self.msl(); - write!(f, " MCH strap length: {msl}, base: 0x{fmsba:08x}") + write!(f, " MCH straps: {msl:2}, base: 0x{fmsba:08x}") } } @@ -167,8 +169,8 @@ pub struct Header { magic: u32, flmap0: FLMAP0, flmap1: FLMAP1, - flmap2: FLMAP2, - flmap3: u32, // TODO + flmap2: FLMAP2, // 100x series + flmap3: u32, // TODO: 500, 600, 800 and 900 series } #[bitfield(u32)] @@ -229,11 +231,13 @@ impl Display for Regions { } } -#[derive(Immutable, IntoBytes, FromBytes, Serialize, Deserialize, Clone, Copy, Debug)] +#[derive(Serialize, Deserialize, Clone)] #[repr(C)] pub struct IFD { pub header: Header, pub regions: Regions, + pub pch_straps: Vec, + pub mch_straps: Vec, } impl Display for IFD { @@ -248,6 +252,46 @@ impl Display for IFD { } } +impl Debug for IFD { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{self}")?; + writeln!(f, "== ICH/PCH Straps ==")?; + for (i, s) in self.pch_straps.iter().enumerate() { + writeln!(f, " {i:2}: {s:08x}")?; + } + writeln!(f, "== MCH Straps ==")?; + for (i, s) in self.mch_straps.iter().enumerate() { + writeln!(f, " {i:2}: {s:08x}")?; + } + write!(f, "") + } +} + +// Extract a bit from a given byte, as bool. +fn extract_bit(byte: u32, bit: u32) -> bool { + byte >> bit & 1 == 1 +} + +impl IFD { + // from + // + pub fn dci(&self) -> bool { + extract_bit(self.pch_straps[0], 17) + } + + pub fn hap(&self) -> bool { + extract_bit(self.pch_straps[0], 16) + } + + pub fn ich_me_disabled(&self) -> bool { + extract_bit(self.pch_straps[0], 0) + } + + pub fn alt_me_disabled(&self) -> bool { + extract_bit(self.pch_straps[10], 7) + } +} + const OFFSET: usize = 16; #[derive(Serialize, Deserialize, Clone, Debug)] @@ -271,6 +315,21 @@ impl IFD { } let (regions, _) = Regions::read_from_prefix(&data[header.flmap0.frba()..]).unwrap(); - Ok(Self { header, regions }) + let count = header.flmap1.isl(); + let slice = &data[header.flmap1.fisba()..]; + let (straps, _) = Ref::<_, [u32]>::from_prefix_with_elems(slice, count).unwrap(); + let pch_straps = straps.to_vec(); + + let count = header.flmap2.msl(); + let slice = &data[header.flmap2.fmsba()..]; + let (straps, _) = Ref::<_, [u32]>::from_prefix_with_elems(slice, count).unwrap(); + let mch_straps = straps.to_vec(); + + Ok(Self { + header, + regions, + mch_straps, + pch_straps, + }) } }