Skip to content

Commit 0ba95ff

Browse files
jlrivasppsurply
authored andcommitted
header: introduce support for server legacy type0 header
This patch introduces the support for decoding Crash Log records from server products that have a legacy header type0. This patch is also introducing a module called `Errata`. The purpose of this module is to indicate scenarios where there could be exceptions or corner cases in the layout. Because this legacy type0 header contains a different layout where the `RecordSize` is allocated, there is the need to use the `Errata` module to indicate whether this scenario is present. Signed-off-by: Rivas Paz, Jose L <[email protected]>
1 parent c4e5fd5 commit 0ba95ff

File tree

6 files changed

+172
-26
lines changed

6 files changed

+172
-26
lines changed

lib/src/errata.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (C) 2025 Intel Corporation
2+
// SPDX-License-Identifier: MIT
3+
4+
use crate::header::Version;
5+
6+
/// Collection of Intel Crash Log erratas
7+
pub struct Errata {
8+
/// Type0 server legacy header
9+
///
10+
/// Some Intel(R) products in the server segment are using legacy Crash Log record headers with
11+
/// Type0, which has a different layout compared with the currently defined Type0 Header.
12+
///
13+
pub type0_legacy_server: bool,
14+
}
15+
16+
impl Errata {
17+
pub fn from_version(version: &Version) -> Self {
18+
let type0_legacy_server = version.header_type == 0 && version.product_id == 0x2f;
19+
20+
Errata {
21+
type0_legacy_server,
22+
}
23+
}
24+
}

lib/src/header.rs

Lines changed: 119 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
#[cfg(feature = "collateral_manager")]
77
use crate::collateral::{CollateralManager, CollateralTree, ItemPath, PVSS};
8+
use crate::errata::Errata;
89
use crate::error::Error;
910
use crate::node::Node;
1011
#[cfg(not(feature = "std"))]
@@ -78,6 +79,16 @@ pub enum HeaderType {
7879
completion_status: Vec<u32>,
7980
collection_complete: bool,
8081
},
82+
83+
Type0LegacyServer {
84+
timestamp: u64,
85+
agent_version: u32,
86+
reason: u32,
87+
die_id: u8,
88+
socket_id: u8,
89+
completion_status: u32,
90+
collection_complete: bool,
91+
},
8192
}
8293

8394
impl HeaderType {
@@ -177,6 +188,36 @@ impl HeaderType {
177188
})
178189
}
179190

191+
fn type0_legacy_server_from_slice(slice: &[u8]) -> Option<Self> {
192+
let reason = u32::from_le_bytes(slice.get(4..8)?.try_into().ok()?);
193+
let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
194+
let agent_version = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
195+
let socket_id = slice[24];
196+
let cs_data = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
197+
let completion_status = cs_data & 0x7FFFFFFF;
198+
let collection_complete = (cs_data >> 31) != 0;
199+
200+
// Encoded die_id
201+
let revision = slice[0];
202+
let die_idx = revision & 0x3;
203+
204+
let die_id = if ((revision >> 7) & 1) == 1 {
205+
die_idx + 9
206+
} else {
207+
die_idx << 2
208+
};
209+
210+
Some(HeaderType::Type0LegacyServer {
211+
timestamp,
212+
agent_version,
213+
reason,
214+
die_id,
215+
socket_id,
216+
completion_status,
217+
collection_complete,
218+
})
219+
}
220+
180221
pub fn from_slice(header_type_value: u16, slice: &[u8]) -> Result<Self, Error> {
181222
match header_type_value {
182223
0 => Ok(HeaderType::Type0),
@@ -189,6 +230,10 @@ impl HeaderType {
189230
type_value => Err(Error::InvalidHeaderType(type_value)),
190231
}
191232
}
233+
234+
pub fn from_slice_type0_legacy_server(slice: &[u8]) -> Result<Self, Error> {
235+
Self::type0_legacy_server_from_slice(slice).ok_or(Error::InvalidHeader)
236+
}
192237
}
193238

194239
/// Header of a Crash Log record
@@ -209,8 +254,19 @@ impl Header {
209254
// Termination marker
210255
return Ok(None);
211256
};
212-
let size = RecordSize::from_slice(slice).ok_or(Error::InvalidHeader)?;
213-
let header_type = HeaderType::from_slice(version.header_type, slice)?;
257+
let errata = Errata::from_version(&version);
258+
259+
let size = if errata.type0_legacy_server {
260+
RecordSize::from_slice_type0_legacy_server(slice).ok_or(Error::InvalidHeader)?
261+
} else {
262+
RecordSize::from_slice(slice).ok_or(Error::InvalidHeader)?
263+
};
264+
265+
let header_type = if errata.type0_legacy_server {
266+
HeaderType::from_slice_type0_legacy_server(slice)?
267+
} else {
268+
HeaderType::from_slice(version.header_type, slice)?
269+
};
214270

215271
Ok(Some(Header {
216272
version,
@@ -280,19 +336,19 @@ impl Header {
280336

281337
/// Returns the ID of the socket that generated the record.
282338
pub fn socket_id(&self) -> u8 {
283-
if let HeaderType::Type6 { socket_id, .. } = self.header_type {
284-
socket_id
285-
} else {
286-
0
339+
match self.header_type {
340+
HeaderType::Type6 { socket_id, .. } => socket_id,
341+
HeaderType::Type0LegacyServer { socket_id, .. } => socket_id,
342+
_ => 0,
287343
}
288344
}
289345

290346
/// Returns the ID of the die that generated the record.
291347
pub fn die_id(&self) -> Option<u8> {
292-
if let HeaderType::Type6 { die_id, .. } = self.header_type {
293-
Some(die_id)
294-
} else {
295-
None
348+
match self.header_type {
349+
HeaderType::Type6 { die_id, .. } => Some(die_id),
350+
HeaderType::Type0LegacyServer { die_id, .. } => Some(die_id),
351+
_ => None,
296352
}
297353
}
298354

@@ -372,6 +428,7 @@ impl Header {
372428
completion_status_size,
373429
..
374430
} => 28 + completion_status_size as usize * 4,
431+
HeaderType::Type0LegacyServer { .. } => 32,
375432
}
376433
}
377434

@@ -380,25 +437,28 @@ impl Header {
380437
&self,
381438
cm: &CollateralManager<T>,
382439
) -> Option<String> {
383-
if let HeaderType::Type6 { socket_id, .. } = self.header_type {
384-
if let Some(die) = self.die(cm) {
385-
Some(format!("processors.cpu{socket_id}.{die}"))
386-
} else {
387-
self.get_root_path()
440+
match self.header_type {
441+
HeaderType::Type6 { socket_id, .. }
442+
| HeaderType::Type0LegacyServer { socket_id, .. } => {
443+
if let Some(die) = self.die(cm) {
444+
Some(format!("processors.cpu{socket_id}.{die}"))
445+
} else {
446+
self.get_root_path()
447+
}
388448
}
389-
} else {
390-
None
449+
_ => None,
391450
}
392451
}
393452

394453
pub(super) fn get_root_path(&self) -> Option<String> {
395-
if let HeaderType::Type6 {
396-
socket_id, die_id, ..
397-
} = self.header_type
398-
{
399-
Some(format!("processors.cpu{socket_id}.die{die_id}"))
400-
} else {
401-
None
454+
match self.header_type {
455+
HeaderType::Type6 {
456+
socket_id, die_id, ..
457+
}
458+
| HeaderType::Type0LegacyServer {
459+
socket_id, die_id, ..
460+
} => Some(format!("processors.cpu{socket_id}.die{die_id}")),
461+
_ => None,
402462
}
403463
}
404464
}
@@ -412,8 +472,13 @@ impl fmt::Display for Header {
412472
);
413473
let header_type = match self.header_type {
414474
HeaderType::Type6 {
415-
die_id, socket_id, ..
416-
} => format!("die_id={die_id}, socket_id={socket_id}"),
475+
socket_id, die_id, ..
476+
}
477+
| HeaderType::Type0LegacyServer {
478+
socket_id, die_id, ..
479+
} => {
480+
format!("die_id={die_id}, socket_id={socket_id}")
481+
}
417482
_ => "..".to_string(),
418483
};
419484

@@ -512,6 +577,14 @@ impl RecordSize {
512577
extended_record_size: u16::from_le_bytes(slice.get(6..8)?.try_into().ok()?),
513578
})
514579
}
580+
581+
/// Creates a [RecordSize] from the raw record of a server product with legacy header type0
582+
pub fn from_slice_type0_legacy_server(slice: &[u8]) -> Option<Self> {
583+
Some(RecordSize {
584+
record_size: u16::from_le_bytes(slice.get(16..18)?.try_into().ok()?),
585+
extended_record_size: 0,
586+
})
587+
}
515588
}
516589

517590
impl From<&RecordSize> for Node {
@@ -641,6 +714,26 @@ impl From<&Header> for Node {
641714
));
642715
}
643716
}
717+
HeaderType::Type0LegacyServer {
718+
timestamp,
719+
agent_version,
720+
reason,
721+
die_id,
722+
socket_id,
723+
completion_status,
724+
collection_complete,
725+
} => {
726+
node.add(Node::field("timestamp", timestamp));
727+
node.add(Node::field("agent_version", agent_version as u64));
728+
node.add(Node::field("reason", reason as u64));
729+
node.add(Node::field("die_id", die_id as u64));
730+
node.add(Node::field("socket_id", socket_id as u64));
731+
node.add(Node::field("completion_status", completion_status as u64));
732+
node.add(Node::field(
733+
"record_collection_completed",
734+
collection_complete as u64,
735+
));
736+
}
644737
_ => (),
645738
}
646739

lib/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ mod bert;
114114
pub mod collateral;
115115
mod cper;
116116
mod crashlog;
117+
pub mod errata;
117118
mod error;
118119
#[cfg(feature = "extraction")]
119120
mod extract;

lib/tests/header.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,15 @@ fn decode_die_id_header() {
7171
let die = header.die(&cm).unwrap();
7272
assert_eq!(die, "io1");
7373
}
74+
75+
#[test]
76+
fn decode_legacy_header_type0() {
77+
let data = fs::read("tests/samples/legacy_type0.crashlog").unwrap();
78+
let header = Header::from_slice(&data).unwrap().unwrap();
79+
80+
let socket_id = header.socket_id();
81+
assert_eq!(socket_id, 1);
82+
83+
let die_id = header.die_id().unwrap();
84+
assert_eq!(die_id, 10);
85+
}

lib/tests/record.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,19 @@ fn box_header_type6() {
238238

239239
assert_eq!(header_type.kind, NodeType::Field { value: 3 })
240240
}
241+
242+
#[test]
243+
fn header_type0_legacy_server() {
244+
let mut cm = CollateralManager::file_system_tree(Path::new(COLLATERAL_TREE_PATH)).unwrap();
245+
let data = fs::read("tests/samples/legacy_type0.crashlog").unwrap();
246+
247+
let crashlog = CrashLog::from_slice(&data).unwrap();
248+
249+
let root = crashlog.decode(&mut cm);
250+
251+
let header_type = root
252+
.get_by_path("processors.cpu1.die10.mca.hdr.version.header_type")
253+
.unwrap();
254+
255+
assert_eq!(header_type.kind, NodeType::Field { value: 0 })
256+
}
48 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)