Skip to content

lib: introduce support for BOX records with header type6 #32

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

Merged
merged 1 commit into from
May 7, 2025
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
11 changes: 10 additions & 1 deletion lib/src/crashlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use std::collections::VecDeque;
#[cfg(target_os = "uefi")]
use uefi_raw::table::system::SystemTable;

use crate::header::HeaderType;
use crate::header::record_types;

/// Set of all the Crash Log records captured on a platform.
Expand Down Expand Up @@ -48,7 +49,15 @@ impl CrashLog {
};

match Region::from_slice(payload) {
Ok(region) => queue.push_front(region),
Ok(mut region) => {
if let HeaderType::Type6 {
socket_id, die_id, ..
} = record.header.header_type
{
region.set_socket_and_die_ids(socket_id, die_id)
};
queue.push_front(region)
}
Err(err) => log::error!("Invalid region in Box record: {err}"),
}
}
Expand Down
15 changes: 12 additions & 3 deletions lib/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,18 @@ impl Header {
/// This requires a [CollateralManager] as the die names are product-specific.
#[cfg(feature = "collateral_manager")]
pub fn die<'a, T: CollateralTree>(&self, cm: &'a CollateralManager<T>) -> Option<&'a str> {
self.get_die_name(&self.die_id()?, cm)
}

#[cfg(feature = "collateral_manager")]
pub(crate) fn get_die_name<'a, T: CollateralTree>(
&self,
die_id: &u8,
cm: &'a CollateralManager<T>,
) -> Option<&'a str> {
let target_info = cm.target_info.get(&self.product_id())?;
let die_id = target_info.die_id.get(&self.die_id()?)?;
Some(die_id)
let die_name = target_info.die_id.get(die_id)?;
Some(die_name)
}

/// Returns the type of the record.
Expand Down Expand Up @@ -367,7 +376,7 @@ impl Header {
}

#[cfg(feature = "collateral_manager")]
pub(super) fn get_root_path_cm<T: CollateralTree>(
pub(super) fn get_root_path_using_cm<T: CollateralTree>(
&self,
cm: &CollateralManager<T>,
) -> Option<String> {
Expand Down
12 changes: 12 additions & 0 deletions lib/src/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@ use crate::header::Header;
use alloc::vec::Vec;

/// A single Crash Log record
#[derive(Default)]
pub struct Record {
/// Header of the record
pub header: Header,
/// Raw content of the record
pub data: Vec<u8>,
/// Additional information provided to the record
pub context: Context,
}

/// Additional data provided to a Crash Log record
#[derive(Clone, Default)]
pub struct Context {
/// Die ID of the record
pub die_id: Option<u8>,
/// Socket ID of the record
pub socket_id: Option<u8>,
}

impl Record {
Expand Down
41 changes: 37 additions & 4 deletions lib/src/record/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::header::record_types;
use crate::node::Node;
use crate::node::NodeType;
#[cfg(not(feature = "std"))]
use alloc::{borrow::ToOwned, str, string::String, vec::Vec};
use alloc::{borrow::ToOwned, format, str, string::String, vec::Vec};
use log::debug;
#[cfg(feature = "std")]
use std::str;
Expand Down Expand Up @@ -70,6 +70,7 @@ impl Record {
/// let record = Record {
/// header: Header::default(),
/// data: vec![0x42],
/// ..Record::default()
/// };
///
/// let csv = "name;offset;size;description;bitfield
Expand Down Expand Up @@ -146,13 +147,13 @@ impl Record {

/// Decodes the [Record] header into a [Node] tree.
pub fn decode_without_cm(&self) -> Node {
let root_path = self.header.get_root_path();
let root_path = self.get_root_path();
self.decode_header(&root_path)
}

#[cfg(feature = "collateral_manager")]
fn decode_header_using_cm<T: CollateralTree>(&self, cm: &mut CollateralManager<T>) -> Node {
let root_path = self.header.get_root_path_cm(cm);
let root_path = self.get_root_path_using_cm(cm);
self.decode_header(&root_path)
}

Expand All @@ -171,6 +172,38 @@ impl Record {
root
}

fn get_root_path(&self) -> Option<String> {
if let Some(custom_root) = self.header.get_root_path() {
return Some(custom_root);
}
if let (Some(socket_id), Some(die_id)) = (self.context.socket_id, self.context.die_id) {
return Some(format!("processors.cpu{socket_id}.die{die_id}"));
}

None
}

#[cfg(feature = "collateral_manager")]
fn get_root_path_using_cm<T: CollateralTree>(
&self,
cm: &mut CollateralManager<T>,
) -> Option<String> {
if let Some(custom_root) = self.header.get_root_path_using_cm(cm) {
return Some(custom_root);
}

if let (Some(socket_id), Some(die_id)) = (self.context.socket_id, self.context.die_id) {
let die = if let Some(die_name) = self.header.get_die_name(&die_id, cm) {
die_name
} else {
&format!("die{die_id}")
};
return Some(format!("processors.cpu{socket_id}.{die}"));
}

None
}

/// Decodes a section of the [Record] located at the given `offset` into a [Node] tree using
/// an arbitrary decode definition stored in the collateral tree.
#[cfg(feature = "collateral_manager")]
Expand All @@ -183,7 +216,7 @@ impl Record {
let paths = self.header.decode_definitions_paths(cm)?;

let mut root = Node::root();
let record_root = if let Some(custom_root) = self.header.get_root_path_cm(cm) {
let record_root = if let Some(custom_root) = self.get_root_path_using_cm(cm) {
root.create_hierarchy(&custom_root)
} else {
&mut root
Expand Down
8 changes: 8 additions & 0 deletions lib/src/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ impl Region {
}
}

pub(crate) fn set_socket_and_die_ids(&mut self, socket_id: u8, die_id: u8) {
for record in self.records.iter_mut() {
record.context.socket_id = Some(socket_id);
record.context.die_id = Some(die_id);
}
}

pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
let mut region = Region::default();
let mut cursor = 0;
Expand Down Expand Up @@ -81,6 +88,7 @@ impl Region {
region.records.push(Record {
header,
data: bytes[cursor..limit.min(bytes.len())].into(),
..Default::default()
});

cursor += record_size;
Expand Down
33 changes: 31 additions & 2 deletions lib/tests/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn basic_decode() {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D,
0x8E, 0x8F,
],
..Default::default()
};

let csv = "name;offset;size;description;bitfield
Expand Down Expand Up @@ -47,6 +48,7 @@ fn relative_paths() {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D,
0x8E, 0x8F,
],
..Default::default()
};

let csv = "name;offset;size;description;bitfield
Expand Down Expand Up @@ -81,7 +83,11 @@ fn decode() {

let data = fs::read("tests/samples/dummy_mca_rev1.crashlog").unwrap();
let header = Header::from_slice(&data).unwrap().unwrap();
let record = Record { header, data };
let record = Record {
header,
data,
..Default::default()
};

let root = record.decode(&mut cm);
let version = root.get_by_path("mca.hdr.version.revision").unwrap();
Expand All @@ -105,6 +111,7 @@ fn decode_generic() {
..Default::default()
},
data: vec![0x42, 0, 0, 0],
..Default::default()
};

let mut cm = CollateralManager::file_system_tree(Path::new(COLLATERAL_TREE_PATH)).unwrap();
Expand All @@ -130,6 +137,7 @@ fn decode_missing_decode_defs() {
..Default::default()
},
data: vec![0x42],
..Default::default()
};

let mut cm = CollateralManager::file_system_tree(Path::new(COLLATERAL_TREE_PATH)).unwrap();
Expand All @@ -148,7 +156,11 @@ fn header_type6_decode() {

let data = fs::read("tests/samples/dummy_mca_rev2.crashlog").unwrap();
let header = Header::from_slice(&data).unwrap().unwrap();
let record = Record { header, data };
let record = Record {
header,
data,
..Default::default()
};

let root = record.decode(&mut cm);
let version = root
Expand Down Expand Up @@ -179,6 +191,7 @@ fn invalid_decode_defs() {
let record = Record {
header: Header::default(),
data: vec![0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87],
..Default::default()
};

let csv = "name;offset;size;description;bitfield
Expand Down Expand Up @@ -209,3 +222,19 @@ foo.bar;8
let field = root.get_by_path("foo.bar").unwrap();
assert_eq!(field.kind, NodeType::Field { value: 0x80 });
}

#[test]
fn box_header_type6() {
let mut cm = CollateralManager::file_system_tree(Path::new(COLLATERAL_TREE_PATH)).unwrap();
let data = fs::read("tests/samples/dummy_mca_rev1_box.crashlog").unwrap();

let crashlog = CrashLog::from_slice(&data).unwrap();

let root = crashlog.decode(&mut cm);

let header_type = root
.get_by_path("processors.cpu1.io0.mca.hdr.version.header_type")
.unwrap();

assert_eq!(header_type.kind, NodeType::Field { value: 3 })
}
Binary file added lib/tests/samples/dummy_mca_rev1_box.crashlog
Binary file not shown.