Skip to content

Commit 0f0e074

Browse files
committed
Support dumping Turin data structures and Milan data structures at the same time.
Fixes <#135>.
1 parent db77d47 commit 0f0e074

9 files changed

+180
-50
lines changed

Cargo.toml

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "amd-apcb"
3-
version = "0.3.3"
3+
version = "0.4.0"
44
authors = ["Oxide Computer"]
55
edition = "2021"
66

@@ -12,14 +12,8 @@ byteorder = { version = "1.4.3", default-features = false }
1212
four-cc = { version = "0.3.0", default-features = false }
1313
memoffset = "0.5"
1414
modular-bitfield = { version = "0.11.2", default-features = false }
15-
#
16-
# In order to use macros as discriminants in enums that make use of derive
17-
# macros (e.g., AsBytes, FromPrimitive), we need the syn crate to have "full"
18-
# enabled. The easiest way to do this is to use num-derive's "full-syntax",
19-
# which passes "full" through to syn.
20-
#
21-
num-derive = { version = "0.3.0", features = [ "full-syntax" ] }
22-
num-traits = { version = "0.2.12", default-features = false }
15+
num-derive = { version = "0.4.2", features = [ ] }
16+
num-traits = { version = "0.2.19", default-features = false }
2317
paste = "1.0"
2418
pre = { version = "0.2.1", default-features = false, features = [] }
2519
static_assertions = "1.1.0"

rust-toolchain

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
22
channel = "nightly-2024-06-19"
3-
components = [ "rustfmt", "rust-src" ]
3+
components = [ "rustfmt", "rust-src", "rust-analyzer" ]

src/apcb.rs

+53-16
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
use crate::types::{Error, FileSystemError, PtrMut, Result};
5+
use crate::types::{ApcbContext, Error, FileSystemError, PtrMut, Result};
66

77
use crate::entry::EntryItemBody;
88
use crate::group::{GroupItem, GroupMutItem};
@@ -50,29 +50,41 @@ use std::borrow::Cow;
5050
#[derive(Clone)]
5151
pub struct ApcbIoOptions {
5252
pub check_checksum: bool,
53+
pub context: ApcbContext,
5354
}
5455

5556
impl Default for ApcbIoOptions {
5657
fn default() -> Self {
57-
Self { check_checksum: true }
58+
Self { check_checksum: true, context: ApcbContext::default() }
5859
}
5960
}
6061

6162
impl ApcbIoOptions {
6263
pub fn builder() -> Self {
6364
Self::default()
6465
}
66+
pub fn check_checksum(&self) -> bool {
67+
self.check_checksum
68+
}
69+
pub fn context(&self) -> ApcbContext {
70+
self.context
71+
}
6572
pub fn with_check_checksum(&mut self, value: bool) -> &mut Self {
6673
self.check_checksum = value;
6774
self
6875
}
76+
pub fn with_context(&mut self, value: ApcbContext) -> &mut Self {
77+
self.context = value;
78+
self
79+
}
6980
pub fn build(&self) -> Self {
7081
self.clone()
7182
}
7283
}
7384

7485
#[cfg_attr(feature = "std", derive(Clone))]
7586
pub struct Apcb<'a> {
87+
context: ApcbContext,
7688
used_size: usize,
7789
pub backing_store: PtrMut<'a, [u8]>,
7890
}
@@ -83,6 +95,11 @@ pub struct Apcb<'a> {
8395
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
8496
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
8597
pub struct SerdeApcb {
98+
/// This field is out-of-band information. At the cost of slight redundancy
99+
/// in user config and another extra field that isn't actually in the blob,
100+
/// we can actually handle the out-of-band information quite natually.
101+
#[cfg_attr(feature = "serde", serde(default))]
102+
pub context: ApcbContext,
86103
pub version: String,
87104
pub header: V2_HEADER,
88105
pub v3_header_ext: Option<V3_HEADER_EXT>,
@@ -110,11 +127,18 @@ impl<'a> schemars::JsonSchema for Apcb<'a> {
110127
use core::convert::TryFrom;
111128

112129
#[cfg(feature = "serde")]
113-
impl<'a> TryFrom<SerdeApcb> for Apcb<'a> {
114-
type Error = Error;
130+
impl<'a> Apcb<'a> {
131+
pub fn context(&self) -> ApcbContext {
132+
self.context
133+
}
134+
// type Error = Error;
115135
fn try_from(serde_apcb: SerdeApcb) -> Result<Self> {
116136
let buf = Cow::from(vec![0xFFu8; Self::MAX_SIZE]);
117-
let mut apcb = Apcb::create(buf, 42, &ApcbIoOptions::default())?;
137+
let mut apcb = Apcb::create(
138+
buf,
139+
42,
140+
&ApcbIoOptions::default().with_context(serde_apcb.context).build(),
141+
)?;
118142
*apcb.header_mut()? = serde_apcb.header;
119143
match serde_apcb.v3_header_ext {
120144
Some(v3) => {
@@ -204,6 +228,7 @@ impl<'a> Serialize for Apcb<'a> {
204228
}
205229
}
206230

231+
/// Note: Caller should probably verify sanity of context() afterwards
207232
#[cfg(feature = "serde")]
208233
impl<'de> Deserialize<'de> for Apcb<'_> {
209234
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
@@ -217,11 +242,13 @@ impl<'de> Deserialize<'de> for Apcb<'_> {
217242
}
218243

219244
pub struct ApcbIterMut<'a> {
245+
context: ApcbContext,
220246
buf: &'a mut [u8],
221247
remaining_used_size: usize,
222248
}
223249

224250
pub struct ApcbIter<'a> {
251+
context: ApcbContext,
225252
buf: &'a [u8],
226253
remaining_used_size: usize,
227254
}
@@ -230,7 +257,10 @@ impl<'a> ApcbIterMut<'a> {
230257
/// It's useful to have some way of NOT mutating self.buf. This is what
231258
/// this function does. Note: The caller needs to manually decrease
232259
/// remaining_used_size for each call if desired.
233-
fn next_item<'b>(buf: &mut &'b mut [u8]) -> Result<GroupMutItem<'b>> {
260+
fn next_item<'b>(
261+
context: ApcbContext,
262+
buf: &mut &'b mut [u8],
263+
) -> Result<GroupMutItem<'b>> {
234264
if buf.is_empty() {
235265
return Err(Error::FileSystem(
236266
FileSystemError::InconsistentHeader,
@@ -256,7 +286,7 @@ impl<'a> ApcbIterMut<'a> {
256286
))?;
257287
let body_len = body.len();
258288

259-
Ok(GroupMutItem { header, buf: body, used_size: body_len })
289+
Ok(GroupMutItem { context, header, buf: body, used_size: body_len })
260290
}
261291

262292
/// Moves the point to the group with the given GROUP_ID. Returns (offset,
@@ -273,12 +303,12 @@ impl<'a> ApcbIterMut<'a> {
273303
if buf.is_empty() {
274304
break;
275305
}
276-
let group = ApcbIterMut::next_item(&mut buf)?;
306+
let group = ApcbIterMut::next_item(self.context, &mut buf)?;
277307
let group_size = group.header.group_size.get();
278308
if group.header.group_id.get() == group_id {
279309
return Ok((offset, group_size as usize));
280310
}
281-
let group = ApcbIterMut::next_item(&mut self.buf)?;
311+
let group = ApcbIterMut::next_item(self.context, &mut self.buf)?;
282312
let group_size = group.header.group_size.get() as usize;
283313
offset = offset
284314
.checked_add(group_size)
@@ -295,7 +325,7 @@ impl<'a> ApcbIterMut<'a> {
295325

296326
pub(crate) fn next1(&mut self) -> Result<GroupMutItem<'a>> {
297327
assert!(self.remaining_used_size != 0, "Internal error");
298-
let item = Self::next_item(&mut self.buf)?;
328+
let item = Self::next_item(self.context, &mut self.buf)?;
299329
let group_size = item.header.group_size.get() as usize;
300330
if group_size <= self.remaining_used_size {
301331
self.remaining_used_size -= group_size;
@@ -324,7 +354,10 @@ impl<'a> ApcbIter<'a> {
324354
/// It's useful to have some way of NOT mutating self.buf. This is what
325355
/// this function does. Note: The caller needs to manually decrease
326356
/// remaining_used_size for each call if desired.
327-
fn next_item<'b>(buf: &mut &'b [u8]) -> Result<GroupItem<'b>> {
357+
fn next_item<'b>(
358+
context: ApcbContext,
359+
buf: &mut &'b [u8],
360+
) -> Result<GroupItem<'b>> {
328361
if buf.is_empty() {
329362
return Err(Error::FileSystem(
330363
FileSystemError::InconsistentHeader,
@@ -351,12 +384,12 @@ impl<'a> ApcbIter<'a> {
351384

352385
let body_len = body.len();
353386

354-
Ok(GroupItem { header, buf: body, used_size: body_len })
387+
Ok(GroupItem { context, header, buf: body, used_size: body_len })
355388
}
356389

357390
pub(crate) fn next1(&mut self) -> Result<GroupItem<'a>> {
358391
assert!(self.remaining_used_size != 0, "Internal error");
359-
let item = Self::next_item(&mut self.buf)?;
392+
let item = Self::next_item(self.context, &mut self.buf)?;
360393
let group_size = item.header.group_size.get() as usize;
361394
if group_size <= self.remaining_used_size {
362395
self.remaining_used_size -= group_size;
@@ -400,7 +433,7 @@ impl<'a> Apcb<'a> {
400433
const ROME_VERSION: u16 = 0x30;
401434
const V3_HEADER_EXT_SIZE: usize =
402435
size_of::<V2_HEADER>() + size_of::<V3_HEADER_EXT>();
403-
pub const MAX_SIZE: usize = 0x6500;
436+
pub const MAX_SIZE: usize = 0x8000;
404437

405438
pub fn header(&self) -> Result<LayoutVerified<&[u8], V2_HEADER>> {
406439
LayoutVerified::<&[u8], V2_HEADER>::new_unaligned_from_prefix(
@@ -509,6 +542,7 @@ impl<'a> Apcb<'a> {
509542

510543
pub fn groups(&self) -> Result<ApcbIter<'_>> {
511544
Ok(ApcbIter {
545+
context: self.context,
512546
buf: self.beginning_of_groups()?,
513547
remaining_used_size: self.used_size,
514548
})
@@ -529,6 +563,7 @@ impl<'a> Apcb<'a> {
529563
pub fn groups_mut(&mut self) -> Result<ApcbIterMut<'_>> {
530564
let used_size = self.used_size;
531565
Ok(ApcbIterMut {
566+
context: self.context,
532567
buf: &mut *self.beginning_of_groups_mut()?,
533568
remaining_used_size: used_size,
534569
})
@@ -1030,6 +1065,7 @@ impl<'a> Apcb<'a> {
10301065
signature: [u8; 4],
10311066
) -> Result<GroupMutItem<'_>> {
10321067
// TODO: insert sorted.
1068+
let context = self.context;
10331069

10341070
if !match group_id {
10351071
GroupId::Psp => signature == *b"PSPG",
@@ -1090,7 +1126,7 @@ impl<'a> Apcb<'a> {
10901126
))?;
10911127
let body_len = body.len();
10921128

1093-
Ok(GroupMutItem { header, buf: body, used_size: body_len })
1129+
Ok(GroupMutItem { context, header, buf: body, used_size: body_len })
10941130
}
10951131

10961132
pub(crate) fn calculate_checksum(
@@ -1263,7 +1299,8 @@ impl<'a> Apcb<'a> {
12631299
));
12641300
}
12651301
}
1266-
let result = Self { backing_store: bs, used_size };
1302+
let result =
1303+
Self { context: options.context(), backing_store: bs, used_size };
12671304

12681305
match result.groups()?.validate() {
12691306
Ok(_) => {}

src/entry.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use crate::ondisk::{
1212
};
1313
use crate::ondisk::{Parameters, ParametersIter};
1414
use crate::tokens_entry::TokensEntryBodyItem;
15-
use crate::types::{Error, FileSystemError, Result};
15+
use crate::types::{
16+
ApcbContext, Error, FileSystemError, MemDfeSearchVersion, Result,
17+
};
1618
use core::marker::PhantomData;
1719
use core::mem::size_of;
1820
use num_traits::FromPrimitive;
@@ -46,6 +48,7 @@ impl<'a> EntryItemBody<&'a mut [u8]> {
4648
pub(crate) fn from_slice(
4749
header: &ENTRY_HEADER,
4850
b: &'a mut [u8],
51+
context: ApcbContext,
4952
) -> Result<EntryItemBody<&'a mut [u8]>> {
5053
let context_type = ContextType::from_u8(header.context_type).ok_or(
5154
Error::FileSystem(
@@ -66,7 +69,7 @@ impl<'a> EntryItemBody<&'a mut [u8]> {
6669
ContextType::Tokens => {
6770
let used_size = b.len();
6871
Ok(Self::Tokens(TokensEntryBodyItem::<&mut [u8]>::new(
69-
header, b, used_size,
72+
header, b, used_size, context,
7073
)?))
7174
}
7275
ContextType::Parameters => Err(Error::EntryTypeMismatch),
@@ -78,6 +81,7 @@ impl<'a> EntryItemBody<&'a [u8]> {
7881
pub(crate) fn from_slice(
7982
header: &ENTRY_HEADER,
8083
b: &'a [u8],
84+
context: ApcbContext,
8185
) -> Result<EntryItemBody<&'a [u8]>> {
8286
let context_type = ContextType::from_u8(header.context_type).ok_or(
8387
Error::FileSystem(
@@ -98,7 +102,7 @@ impl<'a> EntryItemBody<&'a [u8]> {
98102
ContextType::Tokens => {
99103
let used_size = b.len();
100104
Ok(Self::Tokens(TokensEntryBodyItem::<&[u8]>::new(
101-
header, b, used_size,
105+
header, b, used_size, context,
102106
)?))
103107
}
104108
ContextType::Parameters => Err(Error::EntryTypeMismatch),
@@ -117,6 +121,7 @@ impl<'a> EntryItemBody<&'a [u8]> {
117121

118122
#[derive(Debug)]
119123
pub struct EntryMutItem<'a> {
124+
pub(crate) context: ApcbContext,
120125
pub(crate) header: &'a mut ENTRY_HEADER,
121126
pub body: EntryItemBody<&'a mut [u8]>,
122127
}
@@ -420,6 +425,7 @@ use std::fmt;
420425

421426
#[derive(Clone)]
422427
pub struct EntryItem<'a> {
428+
pub(crate) context: ApcbContext,
423429
pub(crate) header: &'a ENTRY_HEADER,
424430
pub body: EntryItemBody<&'a [u8]>,
425431
}
@@ -677,12 +683,6 @@ impl<'a> Serialize for EntryItem<'a> {
677683
} else if let Some(s) = self.body_as_struct_array::<memory::Ddr5CaPinMapElement>() {
678684
let v = s.iter().collect::<Vec<_>>();
679685
state.serialize_field("Ddr5CaPinMapElement", &v)?;
680-
// } else if let Some(s) = self.body_as_struct_array::<memory::MemDfeSearchElement32>() { // UH OH
681-
// let v = s.iter().collect::<Vec<_>>();
682-
// state.serialize_field("MemDfeSearchElement32", &v)?;
683-
} else if let Some(s) = self.body_as_struct_array::<memory::MemDfeSearchElement36>() {
684-
let v = s.iter().collect::<Vec<_>>();
685-
state.serialize_field("MemDfeSearchElement36", &v)?;
686686
} else if let Some(s) = self.body_as_struct_array::<memory::DdrDqPinMapElement>() {
687687
let v = s.iter().collect::<Vec<_>>();
688688
state.serialize_field("DdrDqPinMapElement", &v)?;
@@ -747,7 +747,27 @@ self.body_as_struct_sequence::<memory::platform_tuning::ElementRef<'_>>() {
747747
let v = parameters.collect::<Vec<_>>();
748748
state.serialize_field("parameters", &v)?;
749749
} else {
750-
state.serialize_field("struct_body", &buf)?;
750+
match self.context.mem_dfe_search_version() {
751+
Some(MemDfeSearchVersion::Genoa2) => {
752+
if let Some(s) = self.body_as_struct_array::<memory::MemDfeSearchElement32>() {
753+
let v = s.iter().collect::<Vec<_>>();
754+
state.serialize_field("MemDfeSearchElement32", &v)?;
755+
} else {
756+
state.serialize_field("struct_body", &buf)?;
757+
}
758+
},
759+
Some(MemDfeSearchVersion::Turin1) => {
760+
if let Some(s) = self.body_as_struct_array::<memory::MemDfeSearchElement36>() {
761+
let v = s.iter().collect::<Vec<_>>();
762+
state.serialize_field("MemDfeSearchElement36", &v)?;
763+
} else {
764+
state.serialize_field("struct_body", &buf)?;
765+
}
766+
}
767+
_ => {
768+
state.serialize_field("struct_body", &buf)?;
769+
}
770+
}
751771
}
752772
}
753773
}
@@ -1223,12 +1243,22 @@ impl<'de> Deserialize<'de> for SerdeEntryItem {
12231243
)?;
12241244
}
12251245
Field::MemDfeSearchElement32 => {
1246+
// TODO: maybe also sanity-check
1247+
// context.mem_dfe_search_version()
1248+
// Note: context.mem_dfe_search_version is optional.
1249+
// If it's not specified, it deserialization should
1250+
// still work.
12261251
struct_vec_to_body::<
12271252
memory::MemDfeSearchElement32,
12281253
V,
12291254
>(&mut body, &mut map)?;
12301255
}
12311256
Field::MemDfeSearchElement36 => {
1257+
// TODO: maybe also sanity-check
1258+
// context.mem_dfe_search_version()
1259+
// Note: context.mem_dfe_search_version is optional.
1260+
// If it's not specified, it deserialization should
1261+
// still work.
12321262
struct_vec_to_body::<
12331263
memory::MemDfeSearchElement36,
12341264
V,

0 commit comments

Comments
 (0)