diff --git a/lib/src/errata.rs b/lib/src/errata.rs index 686582a..230a658 100644 --- a/lib/src/errata.rs +++ b/lib/src/errata.rs @@ -29,6 +29,13 @@ pub struct Errata { /// The Crash Log headers have their sizes in DWORDs, but for some products that are using /// ECORE and PCORE Crash Log records, their sizes are written in bytes. pub core_record_size_bytes: bool, + + /// Type0 legacy header + /// + /// Some Intel(R) products in the discrete GPU segment are using legacy Crash Log record + /// headers with type0, which has a different layout compared with the currently defined Type0 + /// Header. + pub type0_legacy_gpu: bool, } const GNR_SP_PRODUCT_ID: u32 = 0x2f; @@ -38,10 +45,25 @@ const CWF_SP_PRODUCT_ID: u32 = 0x8e; const SERVER_LEGACY_PRODUCT_IDS: [u32; 3] = [GNR_SP_PRODUCT_ID, SRF_SP_PRODUCT_ID, CWF_SP_PRODUCT_ID]; +const BMG_X3_PRODUCT_ID: u32 = 0x5d; +const BMG_G31_PRODUCT_ID: u32 = 0x5e; +const BMG_X2_PRODUCT_ID: u32 = 0x5f; +const CRI_PRODUCT_ID: u32 = 0xb6; +const GPU_LEGACY_PRODUCT_IDS: [u32; 4] = [ + BMG_X3_PRODUCT_ID, + BMG_G31_PRODUCT_ID, + BMG_X2_PRODUCT_ID, + CRI_PRODUCT_ID, +]; + impl Errata { pub fn from_version(version: &Version) -> Self { let type0_legacy_server = version.header_type == 0 && SERVER_LEGACY_PRODUCT_IDS.contains(&version.product_id); + + let type0_legacy_gpu = + version.header_type == 0 && GPU_LEGACY_PRODUCT_IDS.contains(&version.product_id); + let type0_legacy_server_box = type0_legacy_server && version.record_type == record_types::PCORE; @@ -52,12 +74,14 @@ impl Errata { && (version.product_id < 0x71 || version.product_id == CGC_PRODUCT_ID); let core_record_size_bytes = !type0_legacy_server + && !type0_legacy_gpu && (ecore_record_with_size_in_bytes || pcore_record_with_size_in_bytes); Errata { type0_legacy_server, type0_legacy_server_box, core_record_size_bytes, + type0_legacy_gpu, } } } diff --git a/lib/src/header.rs b/lib/src/header.rs index 9e7fe33..9062f8f 100644 --- a/lib/src/header.rs +++ b/lib/src/header.rs @@ -89,6 +89,14 @@ pub enum HeaderType { completion_status: u32, collection_complete: bool, }, + + Type0LegacyGpu { + timestamp: u64, + agent_version: u32, + reason: u32, + completion_status: u32, + collection_complete: bool, + }, } impl HeaderType { @@ -218,6 +226,23 @@ impl HeaderType { }) } + fn type0_legacy_gpu_from_slice(slice: &[u8]) -> Option { + let reason = u32::from_le_bytes(slice.get(4..8)?.try_into().ok()?); + let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?); + let agent_version = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?); + let cs_data = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?); + let completion_status = cs_data & 0x7FFFFFFF; + let collection_complete = (cs_data >> 31) != 0; + + Some(HeaderType::Type0LegacyGpu { + timestamp, + agent_version, + reason, + completion_status, + collection_complete, + }) + } + pub fn from_slice(header_type_value: u16, slice: &[u8]) -> Result { match header_type_value { 0 => Ok(HeaderType::Type0), @@ -234,6 +259,10 @@ impl HeaderType { pub fn from_slice_type0_legacy_server(slice: &[u8]) -> Result { Self::type0_legacy_server_from_slice(slice).ok_or(Error::InvalidHeader) } + + pub fn from_slice_type0_legacy_gpu(slice: &[u8]) -> Result { + Self::type0_legacy_gpu_from_slice(slice).ok_or(Error::InvalidHeader) + } } /// Header of a Crash Log record @@ -256,14 +285,16 @@ impl Header { }; let errata = Errata::from_version(&version); - let size = if errata.type0_legacy_server { - RecordSize::from_slice_type0_legacy_server(slice).ok_or(Error::InvalidHeader)? + let size = if errata.type0_legacy_server || errata.type0_legacy_gpu { + RecordSize::from_slice_type0_legacy(slice).ok_or(Error::InvalidHeader)? } else { RecordSize::from_slice(slice).ok_or(Error::InvalidHeader)? }; let header_type = if errata.type0_legacy_server { HeaderType::from_slice_type0_legacy_server(slice)? + } else if errata.type0_legacy_gpu { + HeaderType::from_slice_type0_legacy_gpu(slice)? } else { HeaderType::from_slice(version.header_type, slice)? }; @@ -428,6 +459,7 @@ impl Header { .. } => 28 + completion_status_size as usize * 4, HeaderType::Type0LegacyServer { .. } => 32, + HeaderType::Type0LegacyGpu { .. } => 32, } } @@ -580,8 +612,8 @@ impl RecordSize { }) } - /// Creates a [RecordSize] from the raw record of a server product with legacy header type0 - pub fn from_slice_type0_legacy_server(slice: &[u8]) -> Option { + /// Creates a [RecordSize] from the raw record of a product with legacy header type0 + pub fn from_slice_type0_legacy(slice: &[u8]) -> Option { Some(RecordSize { record_size: u16::from_le_bytes(slice.get(16..18)?.try_into().ok()?), extended_record_size: 0, @@ -736,6 +768,22 @@ impl From<&Header> for Node { collection_complete as u64, )); } + HeaderType::Type0LegacyGpu { + timestamp, + agent_version, + reason, + completion_status, + collection_complete, + } => { + node.add(Node::field("timestamp", timestamp)); + node.add(Node::field("agent_version", agent_version as u64)); + node.add(Node::field("reason", reason as u64)); + node.add(Node::field("completion_status", completion_status as u64)); + node.add(Node::field( + "record_collection_completed", + collection_complete as u64, + )); + } _ => (), } diff --git a/lib/tests/header.rs b/lib/tests/header.rs index 83540b4..d11f812 100644 --- a/lib/tests/header.rs +++ b/lib/tests/header.rs @@ -73,8 +73,8 @@ fn decode_die_id_header() { } #[test] -fn decode_legacy_header_type0() { - let data = fs::read("tests/samples/legacy_type0.crashlog").unwrap(); +fn decode_legacy_header_type0_server() { + let data = fs::read("tests/samples/legacy_type0_server.crashlog").unwrap(); let header = Header::from_slice(&data).unwrap().unwrap(); let socket_id = header.socket_id(); @@ -83,3 +83,23 @@ fn decode_legacy_header_type0() { let die_id = header.die_id().unwrap(); assert_eq!(die_id, 10); } + +#[test] +fn decode_legacy_header_type0_gpu() { + let data = fs::read("tests/samples/legacy_type0_gpu.crashlog").unwrap(); + let header = Header::from_slice(&data).unwrap().unwrap(); + + let socket_id = header.socket_id(); + assert_eq!(socket_id, 0); + + let die_id = header.die_id(); + assert_eq!(die_id, None); + + let node = Node::from(&header); + assert_eq!( + node.get_by_path("record_collection_completed") + .unwrap() + .kind, + NodeType::Field { value: 1 } + ); +} diff --git a/lib/tests/record.rs b/lib/tests/record.rs index b704dfd..383e832 100644 --- a/lib/tests/record.rs +++ b/lib/tests/record.rs @@ -240,7 +240,7 @@ fn box_header_type6() { #[test] fn header_type0_legacy_server() { let mut cm = CollateralManager::file_system_tree(Path::new(COLLATERAL_TREE_PATH)).unwrap(); - let data = fs::read("tests/samples/legacy_type0.crashlog").unwrap(); + let data = fs::read("tests/samples/legacy_type0_server.crashlog").unwrap(); let crashlog = CrashLog::from_slice(&data).unwrap(); diff --git a/lib/tests/samples/legacy_type0_gpu.crashlog b/lib/tests/samples/legacy_type0_gpu.crashlog new file mode 100644 index 0000000..d59d51d Binary files /dev/null and b/lib/tests/samples/legacy_type0_gpu.crashlog differ diff --git a/lib/tests/samples/legacy_type0.crashlog b/lib/tests/samples/legacy_type0_server.crashlog similarity index 100% rename from lib/tests/samples/legacy_type0.crashlog rename to lib/tests/samples/legacy_type0_server.crashlog