Skip to content

Commit bcd9583

Browse files
committed
Construct PspSoftFuseChain bitfield from serde input and/or serialize to serde.
Fixes <#235>.
1 parent 24b52f6 commit bcd9583

File tree

2 files changed

+169
-5
lines changed

2 files changed

+169
-5
lines changed

ahib-config/src/lib.rs

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use amd_efs::flash::Location;
88
use amd_efs::{
99
AddressMode, ComboDirectoryEntryFilter, EfhBulldozerSpiMode,
1010
EfhEspiConfiguration, EfhNaplesSpiMode, EfhRomeSpiMode,
11-
ProcessorGeneration,
11+
ProcessorGeneration, PspSoftFuseChain,
1212
};
1313
use amd_efs::{
1414
BhdDirectoryEntry, BhdDirectoryEntryRegionType, BhdDirectoryEntryType,
@@ -30,6 +30,8 @@ pub enum Error {
3030
Io(std::io::Error),
3131
#[error("image too big")]
3232
ImageTooBig,
33+
#[error("psp entry source {0} unknown")]
34+
PspEntrySourceUnknown(PspDirectoryEntryType),
3335
}
3436

3537
impl From<amd_efs::Error> for Error {
@@ -106,11 +108,125 @@ impl TryFromSerdeDirectoryEntryWithContext<SerdePspDirectoryEntry>
106108
}
107109
}
108110

111+
#[derive(Clone, serde::Serialize, schemars::JsonSchema)]
112+
#[serde(rename = "SerdePspEntrySourceValue")]
113+
#[serde(deny_unknown_fields)]
114+
#[non_exhaustive]
115+
pub enum SerdePspEntrySourceValue {
116+
PspSoftFuseChain(PspSoftFuseChain),
117+
#[serde(deserialize_with = "deserialize_raw")]
118+
Unknown(u64),
119+
}
120+
121+
impl<'de> serde::de::Deserialize<'de> for SerdePspEntrySourceValue {
122+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
123+
where
124+
D: serde::de::Deserializer<'de>,
125+
{
126+
struct PspVisitor;
127+
128+
impl<'de> serde::de::Visitor<'de> for PspVisitor {
129+
type Value = SerdePspEntrySourceValue;
130+
131+
fn expecting(
132+
&self,
133+
formatter: &mut std::fmt::Formatter,
134+
) -> std::fmt::Result {
135+
formatter
136+
.write_str("a u64 or a SerdePspEntrySourceValue variant")
137+
}
138+
139+
fn visit_u64<E>(
140+
self,
141+
value: u64,
142+
) -> std::result::Result<Self::Value, E>
143+
where
144+
E: serde::de::Error,
145+
{
146+
Ok(SerdePspEntrySourceValue::Unknown(value))
147+
}
148+
149+
fn visit_i64<E>(
150+
self,
151+
value: i64,
152+
) -> std::result::Result<Self::Value, E>
153+
where
154+
E: serde::de::Error,
155+
{
156+
if value >= 0 {
157+
Ok(SerdePspEntrySourceValue::Unknown(value as u64))
158+
} else {
159+
Err(E::invalid_value(
160+
serde::de::Unexpected::Signed(value),
161+
&"a positive integer or SerdePspEntrySourceValue variant",
162+
))
163+
}
164+
}
165+
166+
fn visit_map<A>(
167+
self,
168+
mut map: A,
169+
) -> std::result::Result<Self::Value, A::Error>
170+
where
171+
A: serde::de::MapAccess<'de>,
172+
{
173+
if let Some(key) = map.next_key::<String>()? {
174+
match key.as_str() {
175+
"PspSoftFuseChain" => {
176+
Ok(SerdePspEntrySourceValue::PspSoftFuseChain(
177+
map.next_value::<PspSoftFuseChain>()?,
178+
))
179+
}
180+
_ => Err(serde::de::Error::custom(
181+
"expected SerdePspEntrySourceValue variant",
182+
)),
183+
}
184+
} else {
185+
Err(serde::de::Error::custom(
186+
"expected SerdePspEntrySourceValue variant",
187+
))
188+
}
189+
}
190+
}
191+
192+
deserializer.deserialize_any(PspVisitor)
193+
}
194+
}
195+
196+
impl SerdePspEntrySourceValue {
197+
pub fn from_u64(value: u64, typ: PspDirectoryEntryType) -> Self {
198+
match typ {
199+
PspDirectoryEntryType::PspSoftFuseChain => {
200+
Self::PspSoftFuseChain(PspSoftFuseChain::from(value))
201+
}
202+
_ => SerdePspEntrySourceValue::Unknown(value),
203+
}
204+
}
205+
206+
pub fn to_u64(
207+
&self,
208+
typ_or_err: std::result::Result<PspDirectoryEntryType, amd_efs::Error>,
209+
) -> Result<u64> {
210+
if let SerdePspEntrySourceValue::Unknown(x) = self {
211+
Ok(*x)
212+
} else {
213+
let typ = typ_or_err.unwrap();
214+
match typ {
215+
PspDirectoryEntryType::PspSoftFuseChain => match self {
216+
Self::PspSoftFuseChain(x) => Ok(u64::from(*x)),
217+
_ => Err(Error::PspEntrySourceUnknown(typ)),
218+
},
219+
_ => Err(Error::PspEntrySourceUnknown(typ)),
220+
}
221+
}
222+
}
223+
}
224+
109225
#[derive(Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
110226
#[serde(rename = "PspEntrySource")]
111227
#[serde(deny_unknown_fields)]
112228
pub enum SerdePspEntrySource {
113-
Value(u64),
229+
Value(SerdePspEntrySourceValue),
114230
BlobFile(PathBuf),
115231
SecondLevelDirectory(SerdePspDirectory),
116232
}

src/main.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use amd_efs::{
66
ProcessorGeneration, PspDirectory, PspDirectoryEntry,
77
PspDirectoryEntryType, PspDirectoryHeader, ValueOrLocation,
88
};
9+
use amd_host_image_builder_config::SerdePspEntrySourceValue;
910
use amd_host_image_builder_config::{
1011
Error, Result, SerdeBhdDirectory, SerdeBhdDirectoryEntry,
1112
SerdeBhdDirectoryEntryAttrs, SerdeBhdDirectoryEntryBlob,
@@ -56,6 +57,53 @@ fn test_bitfield_serde() {
5657
assert_eq!(result.address_mode(), AddressMode::PhysicalAddress);
5758
}
5859

60+
#[test]
61+
fn test_valid_compat_serde_psp_entry_source_value_deserialization() {
62+
let json = "16"; // force_security_policy_loading_even_if_insecure
63+
let result =
64+
serde_json::from_str::<SerdePspEntrySourceValue>(json).unwrap();
65+
if let SerdePspEntrySourceValue::Unknown(x) = result {
66+
assert_eq!(x, 16);
67+
} else {
68+
panic!("got the wrong SerdePspEntrySourceValue variant")
69+
}
70+
}
71+
72+
#[test]
73+
fn test_valid_serde_psp_entry_source_value_deserialization() {
74+
use amd_efs::PspSoftFuseChain32MiBSpiDecoding;
75+
use amd_efs::PspSoftFuseChainPostCodeDecoding;
76+
let json = r#"{"PspSoftFuseChain": {"early_secure_debug_unlock": true, "spi_decoding": "UpperHalf", "postcode_decoding": "Lpc"}}"#;
77+
let result =
78+
serde_json::from_str::<SerdePspEntrySourceValue>(json).unwrap();
79+
if let SerdePspEntrySourceValue::PspSoftFuseChain(x) = result {
80+
assert_eq!(
81+
x.spi_decoding(),
82+
PspSoftFuseChain32MiBSpiDecoding::UpperHalf
83+
);
84+
assert_eq!(
85+
x.postcode_decoding(),
86+
PspSoftFuseChainPostCodeDecoding::Lpc
87+
);
88+
assert!(x.early_secure_debug_unlock());
89+
assert!(!x.force_recovery_booting());
90+
} else {
91+
panic!("got the wrong SerdePspEntrySourceValue variant")
92+
}
93+
}
94+
95+
#[test]
96+
fn test_invalid_string_deserialization() {
97+
let json = r#""x""#;
98+
assert!(serde_json::from_str::<SerdePspEntrySourceValue>(json).is_err());
99+
}
100+
101+
#[test]
102+
fn test_invalid_wrong_key_name() {
103+
let json = r#"{"WrongName": {"some": "data"}}"#;
104+
assert!(serde_json::from_str::<SerdePspEntrySourceValue>(json).is_err());
105+
}
106+
59107
mod hole;
60108
use hole::Hole;
61109

@@ -622,7 +670,7 @@ fn dump_psp_directory<T: FlashRead + FlashWrite>(
622670
// TODO: Handle the other variant (PspComboDirectory)
623671
let mut blob_dump_filenames = HashSet::<PathBuf>::new();
624672
SerdePspDirectoryVariant::PspDirectory(SerdePspDirectory {
625-
entries: psp_directory.entries().map_while(|e| {
673+
entries: psp_directory.entries().map_while(|e| -> Option<SerdePspEntry> {
626674
if let Ok(typ) = e.typ_or_err() {
627675
match typ {
628676
PspDirectoryEntryType::SecondLevelDirectory => {
@@ -684,7 +732,7 @@ fn dump_psp_directory<T: FlashRead + FlashWrite>(
684732
}
685733
None => {
686734
let value = e.value().unwrap();
687-
SerdePspEntrySource::Value(value)
735+
SerdePspEntrySource::Value(SerdePspEntrySourceValue::from_u64(value, typ))
688736
}
689737
},
690738
target: SerdePspDirectoryEntry {
@@ -1096,7 +1144,7 @@ fn prepare_psp_directory_contents(
10961144
SerdePspEntrySource::Value(x) => {
10971145
// FIXME: assert!(blob_slot_settings.is_none()); fails for some reason
10981146
// DirectoryRelativeOffset is the one that can always be overridden
1099-
raw_entry.set_source(AddressMode::DirectoryRelativeOffset, ValueOrLocation::Value(x)).unwrap();
1147+
raw_entry.set_source(AddressMode::DirectoryRelativeOffset, ValueOrLocation::Value(x.to_u64(raw_entry.typ_or_err()).unwrap())).unwrap();
11001148
vec![(raw_entry, None, None)]
11011149
}
11021150
SerdePspEntrySource::BlobFile(

0 commit comments

Comments
 (0)