Skip to content
Merged
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
98 changes: 84 additions & 14 deletions src/ifd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
//!
//! The IFD was extended over time; for reference,
//! see <https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/io-controller-hub-8-datasheet.pdf>
//! and <https://www.intel.com/content/dam/doc/datasheet/7300-chipset-memory-controller-hub-datasheet.pdf>
//! and <https://www.intel.com/content/www/us/en/content-details/332690/intel-100-series-chipset-family-platform-controller-hub-pch-datasheet-volume-1.html>
//! and <https://www.intel.com/content/www/us/en/content-details/332691/intel-100-series-chipset-family-platform-controller-hub-pch-datasheet-volume-2.html>
//! and <https://edc.intel.com/content/www/us/en/design/ipla/software-development-platforms/client/platforms/alder-lake-mobile-p/intel-600-series-chipset-family-on-package-platform-controller-hub-pch-datash/002/>
//! and <https://www.intel.com/content/www/us/en/content-details/710279/intel-600-series-and-intel-700-series-chipset-family-on-package-platform-controller-hub-pch-datasheet-volume-2-of-2.html>
//! and <https://opensecuritytraining.info/IntroBIOS_files/Day2_02_Advanced%20x86%20-%20BIOS%20and%20SMM%20Internals%20-%20Flash%20Descriptor.pdf>
//! 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
Expand All @@ -26,16 +33,20 @@
//! | 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.
//! <https://edc.intel.com/content/www/us/en/design/ipla/software-development-platforms/client/platforms/alder-lake-mobile-p/intel-600-series-chipset-family-on-package-platform-controller-hub-pch-datash/serial-peripheral-interface-spi/>

// We retain the all-uppercase acronyms in the struct definitions.
// 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.
Expand Down Expand Up @@ -78,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}")
}
}
Expand Down Expand Up @@ -119,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}")
}
}

Expand All @@ -142,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}")
}
}

Expand All @@ -156,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)]
Expand Down Expand Up @@ -218,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<u32>,
pub mch_straps: Vec<u32>,
}

impl Display for IFD {
Expand All @@ -237,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 <https://review.coreboot.org/c/coreboot/+/82272>
// <https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/700-series-chipset-family-platform-controller-hub-datasheet-volume-1-of/004/intel-direct-connect-interface-dci/>
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)]
Expand All @@ -260,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,
})
}
}