Skip to content

Commit a0f3645

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

File tree

7 files changed

+180
-43
lines changed

7 files changed

+180
-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

+55-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,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) => {
@@ -217,11 +241,13 @@ impl<'de> Deserialize<'de> for Apcb<'_> {
217241
}
218242

219243
pub struct ApcbIterMut<'a> {
244+
context: ApcbContext,
220245
buf: &'a mut [u8],
221246
remaining_used_size: usize,
222247
}
223248

224249
pub struct ApcbIter<'a> {
250+
context: ApcbContext,
225251
buf: &'a [u8],
226252
remaining_used_size: usize,
227253
}
@@ -230,7 +256,10 @@ impl<'a> ApcbIterMut<'a> {
230256
/// It's useful to have some way of NOT mutating self.buf. This is what
231257
/// this function does. Note: The caller needs to manually decrease
232258
/// remaining_used_size for each call if desired.
233-
fn next_item<'b>(buf: &mut &'b mut [u8]) -> Result<GroupMutItem<'b>> {
259+
fn next_item<'b>(
260+
context: ApcbContext,
261+
buf: &mut &'b mut [u8],
262+
) -> Result<GroupMutItem<'b>> {
234263
if buf.is_empty() {
235264
return Err(Error::FileSystem(
236265
FileSystemError::InconsistentHeader,
@@ -256,7 +285,7 @@ impl<'a> ApcbIterMut<'a> {
256285
))?;
257286
let body_len = body.len();
258287

259-
Ok(GroupMutItem { header, buf: body, used_size: body_len })
288+
Ok(GroupMutItem { context, header, buf: body, used_size: body_len })
260289
}
261290

262291
/// Moves the point to the group with the given GROUP_ID. Returns (offset,
@@ -273,12 +302,12 @@ impl<'a> ApcbIterMut<'a> {
273302
if buf.is_empty() {
274303
break;
275304
}
276-
let group = ApcbIterMut::next_item(&mut buf)?;
305+
let group = ApcbIterMut::next_item(self.context, &mut buf)?;
277306
let group_size = group.header.group_size.get();
278307
if group.header.group_id.get() == group_id {
279308
return Ok((offset, group_size as usize));
280309
}
281-
let group = ApcbIterMut::next_item(&mut self.buf)?;
310+
let group = ApcbIterMut::next_item(self.context, &mut self.buf)?;
282311
let group_size = group.header.group_size.get() as usize;
283312
offset = offset
284313
.checked_add(group_size)
@@ -295,7 +324,7 @@ impl<'a> ApcbIterMut<'a> {
295324

296325
pub(crate) fn next1(&mut self) -> Result<GroupMutItem<'a>> {
297326
assert!(self.remaining_used_size != 0, "Internal error");
298-
let item = Self::next_item(&mut self.buf)?;
327+
let item = Self::next_item(self.context, &mut self.buf)?;
299328
let group_size = item.header.group_size.get() as usize;
300329
if group_size <= self.remaining_used_size {
301330
self.remaining_used_size -= group_size;
@@ -324,7 +353,10 @@ impl<'a> ApcbIter<'a> {
324353
/// It's useful to have some way of NOT mutating self.buf. This is what
325354
/// this function does. Note: The caller needs to manually decrease
326355
/// remaining_used_size for each call if desired.
327-
fn next_item<'b>(buf: &mut &'b [u8]) -> Result<GroupItem<'b>> {
356+
fn next_item<'b>(
357+
context: ApcbContext,
358+
buf: &mut &'b [u8],
359+
) -> Result<GroupItem<'b>> {
328360
if buf.is_empty() {
329361
return Err(Error::FileSystem(
330362
FileSystemError::InconsistentHeader,
@@ -351,12 +383,12 @@ impl<'a> ApcbIter<'a> {
351383

352384
let body_len = body.len();
353385

354-
Ok(GroupItem { header, buf: body, used_size: body_len })
386+
Ok(GroupItem { context, header, buf: body, used_size: body_len })
355387
}
356388

357389
pub(crate) fn next1(&mut self) -> Result<GroupItem<'a>> {
358390
assert!(self.remaining_used_size != 0, "Internal error");
359-
let item = Self::next_item(&mut self.buf)?;
391+
let item = Self::next_item(self.context, &mut self.buf)?;
360392
let group_size = item.header.group_size.get() as usize;
361393
if group_size <= self.remaining_used_size {
362394
self.remaining_used_size -= group_size;
@@ -369,7 +401,7 @@ impl<'a> ApcbIter<'a> {
369401
}
370402
}
371403
/// Validates the entries (recursively). Also consumes iterator.
372-
pub(crate) fn validate(mut self) -> Result<()> {
404+
pub(crate) fn validate(mut self, context: ApcbContext) -> Result<()> {
373405
while self.remaining_used_size > 0 {
374406
let item = self.next1()?;
375407
GroupId::from_u16(item.header.group_id.get()).ok_or(
@@ -509,6 +541,7 @@ impl<'a> Apcb<'a> {
509541

510542
pub fn groups(&self) -> Result<ApcbIter<'_>> {
511543
Ok(ApcbIter {
544+
context: self.context,
512545
buf: self.beginning_of_groups()?,
513546
remaining_used_size: self.used_size,
514547
})
@@ -522,13 +555,14 @@ impl<'a> Apcb<'a> {
522555
/// If ABL0_VERSION is Some, also validates against that AGESA
523556
/// bootloader version.
524557
pub fn validate(&self, abl0_version: Option<u32>) -> Result<()> {
525-
self.groups()?.validate()?;
558+
self.groups()?.validate(self.context)?;
526559
self.ensure_abl0_compatibility(abl0_version)
527560
}
528561

529562
pub fn groups_mut(&mut self) -> Result<ApcbIterMut<'_>> {
530563
let used_size = self.used_size;
531564
Ok(ApcbIterMut {
565+
context: self.context,
532566
buf: &mut *self.beginning_of_groups_mut()?,
533567
remaining_used_size: used_size,
534568
})
@@ -1030,6 +1064,7 @@ impl<'a> Apcb<'a> {
10301064
signature: [u8; 4],
10311065
) -> Result<GroupMutItem<'_>> {
10321066
// TODO: insert sorted.
1067+
let context = self.context;
10331068

10341069
if !match group_id {
10351070
GroupId::Psp => signature == *b"PSPG",
@@ -1090,7 +1125,7 @@ impl<'a> Apcb<'a> {
10901125
))?;
10911126
let body_len = body.len();
10921127

1093-
Ok(GroupMutItem { header, buf: body, used_size: body_len })
1128+
Ok(GroupMutItem { context, header, buf: body, used_size: body_len })
10941129
}
10951130

10961131
pub(crate) fn calculate_checksum(
@@ -1263,9 +1298,11 @@ impl<'a> Apcb<'a> {
12631298
));
12641299
}
12651300
}
1266-
let result = Self { backing_store: bs, used_size };
1301+
let result =
1302+
Self { context: options.context(), backing_store: bs, used_size };
12671303

1268-
match result.groups()?.validate() {
1304+
let context = options.context();
1305+
match result.groups()?.validate(context) {
12691306
Ok(_) => {}
12701307
Err(e) => {
12711308
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)