Skip to content

Commit 52d5883

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

File tree

7 files changed

+177
-43
lines changed

7 files changed

+177
-43
lines changed

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

+52-18
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,15 @@ 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+
// type Error = Error;
115132
fn try_from(serde_apcb: SerdeApcb) -> Result<Self> {
116133
let buf = Cow::from(vec![0xFFu8; Self::MAX_SIZE]);
117-
let mut apcb = Apcb::create(buf, 42, &ApcbIoOptions::default())?;
134+
let mut apcb = Apcb::create(
135+
buf,
136+
42,
137+
&ApcbIoOptions::default().with_context(serde_apcb.context).build(),
138+
)?;
118139
*apcb.header_mut()? = serde_apcb.header;
119140
match serde_apcb.v3_header_ext {
120141
Some(v3) => {
@@ -217,11 +238,13 @@ impl<'de> Deserialize<'de> for Apcb<'_> {
217238
}
218239

219240
pub struct ApcbIterMut<'a> {
241+
context: ApcbContext,
220242
buf: &'a mut [u8],
221243
remaining_used_size: usize,
222244
}
223245

224246
pub struct ApcbIter<'a> {
247+
context: ApcbContext,
225248
buf: &'a [u8],
226249
remaining_used_size: usize,
227250
}
@@ -230,7 +253,10 @@ impl<'a> ApcbIterMut<'a> {
230253
/// It's useful to have some way of NOT mutating self.buf. This is what
231254
/// this function does. Note: The caller needs to manually decrease
232255
/// remaining_used_size for each call if desired.
233-
fn next_item<'b>(buf: &mut &'b mut [u8]) -> Result<GroupMutItem<'b>> {
256+
fn next_item<'b>(
257+
context: ApcbContext,
258+
buf: &mut &'b mut [u8],
259+
) -> Result<GroupMutItem<'b>> {
234260
if buf.is_empty() {
235261
return Err(Error::FileSystem(
236262
FileSystemError::InconsistentHeader,
@@ -256,7 +282,7 @@ impl<'a> ApcbIterMut<'a> {
256282
))?;
257283
let body_len = body.len();
258284

259-
Ok(GroupMutItem { header, buf: body, used_size: body_len })
285+
Ok(GroupMutItem { context, header, buf: body, used_size: body_len })
260286
}
261287

262288
/// Moves the point to the group with the given GROUP_ID. Returns (offset,
@@ -273,12 +299,12 @@ impl<'a> ApcbIterMut<'a> {
273299
if buf.is_empty() {
274300
break;
275301
}
276-
let group = ApcbIterMut::next_item(&mut buf)?;
302+
let group = ApcbIterMut::next_item(self.context, &mut buf)?;
277303
let group_size = group.header.group_size.get();
278304
if group.header.group_id.get() == group_id {
279305
return Ok((offset, group_size as usize));
280306
}
281-
let group = ApcbIterMut::next_item(&mut self.buf)?;
307+
let group = ApcbIterMut::next_item(self.context, &mut self.buf)?;
282308
let group_size = group.header.group_size.get() as usize;
283309
offset = offset
284310
.checked_add(group_size)
@@ -295,7 +321,7 @@ impl<'a> ApcbIterMut<'a> {
295321

296322
pub(crate) fn next1(&mut self) -> Result<GroupMutItem<'a>> {
297323
assert!(self.remaining_used_size != 0, "Internal error");
298-
let item = Self::next_item(&mut self.buf)?;
324+
let item = Self::next_item(self.context, &mut self.buf)?;
299325
let group_size = item.header.group_size.get() as usize;
300326
if group_size <= self.remaining_used_size {
301327
self.remaining_used_size -= group_size;
@@ -324,7 +350,10 @@ impl<'a> ApcbIter<'a> {
324350
/// It's useful to have some way of NOT mutating self.buf. This is what
325351
/// this function does. Note: The caller needs to manually decrease
326352
/// remaining_used_size for each call if desired.
327-
fn next_item<'b>(buf: &mut &'b [u8]) -> Result<GroupItem<'b>> {
353+
fn next_item<'b>(
354+
context: ApcbContext,
355+
buf: &mut &'b [u8],
356+
) -> Result<GroupItem<'b>> {
328357
if buf.is_empty() {
329358
return Err(Error::FileSystem(
330359
FileSystemError::InconsistentHeader,
@@ -351,12 +380,12 @@ impl<'a> ApcbIter<'a> {
351380

352381
let body_len = body.len();
353382

354-
Ok(GroupItem { header, buf: body, used_size: body_len })
383+
Ok(GroupItem { context, header, buf: body, used_size: body_len })
355384
}
356385

357386
pub(crate) fn next1(&mut self) -> Result<GroupItem<'a>> {
358387
assert!(self.remaining_used_size != 0, "Internal error");
359-
let item = Self::next_item(&mut self.buf)?;
388+
let item = Self::next_item(self.context, &mut self.buf)?;
360389
let group_size = item.header.group_size.get() as usize;
361390
if group_size <= self.remaining_used_size {
362391
self.remaining_used_size -= group_size;
@@ -369,7 +398,7 @@ impl<'a> ApcbIter<'a> {
369398
}
370399
}
371400
/// Validates the entries (recursively). Also consumes iterator.
372-
pub(crate) fn validate(mut self) -> Result<()> {
401+
pub(crate) fn validate(mut self, context: ApcbContext) -> Result<()> {
373402
while self.remaining_used_size > 0 {
374403
let item = self.next1()?;
375404
GroupId::from_u16(item.header.group_id.get()).ok_or(
@@ -509,6 +538,7 @@ impl<'a> Apcb<'a> {
509538

510539
pub fn groups(&self) -> Result<ApcbIter<'_>> {
511540
Ok(ApcbIter {
541+
context: self.context,
512542
buf: self.beginning_of_groups()?,
513543
remaining_used_size: self.used_size,
514544
})
@@ -522,13 +552,14 @@ impl<'a> Apcb<'a> {
522552
/// If ABL0_VERSION is Some, also validates against that AGESA
523553
/// bootloader version.
524554
pub fn validate(&self, abl0_version: Option<u32>) -> Result<()> {
525-
self.groups()?.validate()?;
555+
self.groups()?.validate(self.context)?;
526556
self.ensure_abl0_compatibility(abl0_version)
527557
}
528558

529559
pub fn groups_mut(&mut self) -> Result<ApcbIterMut<'_>> {
530560
let used_size = self.used_size;
531561
Ok(ApcbIterMut {
562+
context: self.context,
532563
buf: &mut *self.beginning_of_groups_mut()?,
533564
remaining_used_size: used_size,
534565
})
@@ -1030,6 +1061,7 @@ impl<'a> Apcb<'a> {
10301061
signature: [u8; 4],
10311062
) -> Result<GroupMutItem<'_>> {
10321063
// TODO: insert sorted.
1064+
let context = self.context;
10331065

10341066
if !match group_id {
10351067
GroupId::Psp => signature == *b"PSPG",
@@ -1090,7 +1122,7 @@ impl<'a> Apcb<'a> {
10901122
))?;
10911123
let body_len = body.len();
10921124

1093-
Ok(GroupMutItem { header, buf: body, used_size: body_len })
1125+
Ok(GroupMutItem { context, header, buf: body, used_size: body_len })
10941126
}
10951127

10961128
pub(crate) fn calculate_checksum(
@@ -1263,9 +1295,11 @@ impl<'a> Apcb<'a> {
12631295
));
12641296
}
12651297
}
1266-
let result = Self { backing_store: bs, used_size };
1298+
let result =
1299+
Self { context: options.context(), backing_store: bs, used_size };
12671300

1268-
match result.groups()?.validate() {
1301+
let context = options.context();
1302+
match result.groups()?.validate(context) {
12691303
Ok(_) => {}
12701304
Err(e) => {
12711305
return Err(e);

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) => { // UH OH
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)