1use crate::util::parse_int::ParseInt;
6
7use std::fmt;
8use std::path::Path;
9
10use anyhow::{Result, anyhow, bail};
11
12use serde::de::{self, Unexpected};
13use serde::{Deserialize, Serialize};
14
15use serde_annotate::Annotate;
16
17#[derive(Annotate, Serialize, Debug, PartialEq, Eq)]
18#[serde(untagged)]
19pub enum OtpImgValue {
20 Word(u64),
21 Bool(bool),
22 Sequence(Vec<u32>),
23 #[serde(serialize_with = "serialize_random")]
24 Random,
25}
26
27fn serialize_random<S>(serializer: S) -> Result<S::Ok, S::Error>
28where
29 S: serde::Serializer,
30{
31 serializer.serialize_str("<random>")
32}
33
34impl<'de> Deserialize<'de> for OtpImgValue {
35 fn deserialize<D>(deserializer: D) -> Result<OtpImgValue, D::Error>
36 where
37 D: serde::Deserializer<'de>,
38 {
39 struct Visitor;
40
41 impl<'a> de::Visitor<'a> for Visitor {
42 type Value = OtpImgValue;
43
44 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
45 formatter.write_str("an OtpImgValue")
46 }
47
48 fn visit_str<E>(self, val: &str) -> Result<Self::Value, E>
49 where
50 E: de::Error,
51 {
52 Ok(match val {
53 "<random>" => OtpImgValue::Random,
54 "true" => OtpImgValue::Bool(true),
55 "false" => OtpImgValue::Bool(false),
56 _ => OtpImgValue::Word(
57 u64::from_str(val)
58 .map_err(|_| de::Error::invalid_value(Unexpected::Str(val), &self))?,
59 ),
60 })
61 }
62
63 fn visit_u64<E>(self, val: u64) -> Result<Self::Value, E>
64 where
65 E: de::Error,
66 {
67 Ok(OtpImgValue::Word(val))
68 }
69
70 fn visit_bool<E>(self, val: bool) -> Result<Self::Value, E>
71 where
72 E: de::Error,
73 {
74 Ok(OtpImgValue::Bool(val))
75 }
76
77 fn visit_seq<A>(self, mut val: A) -> Result<Self::Value, A::Error>
78 where
79 A: de::SeqAccess<'a>,
80 {
81 let mut res = Vec::<u32>::new();
82 while let Ok(Some(v)) = val.next_element::<String>() {
83 res.push(
84 u32::from_str(&v)
85 .map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &self))?,
86 )
87 }
88 Ok(OtpImgValue::Sequence(res))
89 }
90 }
91 deserializer.deserialize_any(Visitor {})
92 }
93}
94
95#[derive(Annotate, Serialize, Deserialize, Debug, PartialEq, Eq)]
96pub struct OtpImgItem {
97 pub name: String,
98 pub value: OtpImgValue,
99}
100
101#[derive(Annotate, Serialize, Deserialize, Debug, PartialEq, Eq)]
102pub struct OtpImgPartition {
103 pub name: String,
104 pub items: Option<Vec<OtpImgItem>>,
105}
106
107#[derive(Annotate, Serialize, Deserialize, Debug, PartialEq, Eq)]
108pub struct OtpImg {
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub seed: Option<u64>,
111 #[annotate(format = hex)]
114 pub partitions: Vec<OtpImgPartition>,
115}
116
117pub trait OtpRead {
118 fn read32(&self, name: &str) -> Result<u32> {
119 self.read32_offset(name, 0)
120 }
121
122 fn read32_offset(&self, name: &str, offset: usize) -> Result<u32>;
123}
124
125impl OtpRead for OtpImg {
126 fn read32_offset(&self, name: &str, offset: usize) -> Result<u32> {
127 if !offset.is_multiple_of(4) {
128 bail!("offset not word aligned");
129 }
130 Ok(
131 match self
133 .partitions
134 .iter()
135 .filter_map(|p| p.items.as_ref())
136 .flatten()
137 .find(|v| v.name == name)
138 .map(|item| &item.value)
139 {
140 Some(OtpImgValue::Word(v)) => {
141 if offset == 0 {
142 (v & u32::MAX as u64).try_into().unwrap()
143 } else if offset == 4 {
144 (v >> 32).try_into().unwrap()
145 } else {
146 bail!("invalid OTP address {} + {:#08x}", name, offset)
147 }
148 }
149 Some(OtpImgValue::Sequence(v)) => *v
150 .get(offset / 4)
151 .ok_or_else(|| anyhow!("invalid OTP address {} + {:#08x}", name, offset))?,
152 None => bail!("undefined OTP word {}", name),
153 Some(x) => bail!("invalid OTP word {} = {:?}", name, x),
154 },
155 )
156 }
157}
158
159impl OtpImg {
160 pub fn from_file(in_file: &Path) -> Result<OtpImg> {
161 use std::str::FromStr;
162 Self::from_str(&std::fs::read_to_string(in_file)?)
163 }
164}
165
166impl std::str::FromStr for OtpImg {
167 type Err = anyhow::Error;
168
169 fn from_str(json_text: &str) -> Result<OtpImg> {
170 let res: OtpImg = deser_hjson::from_str(json_text)?;
171 Ok(res)
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use std::str::FromStr;
179 use std::sync::LazyLock;
180
181 use serde_annotate::serialize;
182
183 const TEST_OTP_JSON: &str = r#"
184 {
185 partitions: [
186 {
187 name: "CREATOR_SW_CFG",
188 items: [
189 {
190 name: "CREATOR_SW_CFG_DIGEST",
191 value: 0,
192 },
193 {
194 name: "CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN",
195 value: "0x4b4b4b4b4b4ba5a5",
196 },
197 {
198 name: "CREATOR_RANDOM",
199 value: "<random>",
200 },
201 {
202 name: "CREATOR_SEQ",
203 value: [
204 "0xab",
205 "0xcd",
206 "0xef",
207 ],
208 },
209 ]
210 }
211 ]
212 }"#;
213
214 static TEST_OTP: LazyLock<OtpImg> = LazyLock::new(|| OtpImg {
215 seed: None,
216 partitions: vec![OtpImgPartition {
217 name: "CREATOR_SW_CFG".to_owned(),
218 items: Some(vec![
219 OtpImgItem {
220 name: "CREATOR_SW_CFG_DIGEST".to_owned(),
221 value: OtpImgValue::Word(0x0),
222 },
223 OtpImgItem {
224 name: "CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN".to_owned(),
225 value: OtpImgValue::Word(0x4b4b4b4b4b4ba5a5),
226 },
227 OtpImgItem {
228 name: "CREATOR_RANDOM".to_owned(),
229 value: OtpImgValue::Random,
230 },
231 OtpImgItem {
232 name: "CREATOR_SEQ".to_owned(),
233 value: OtpImgValue::Sequence(vec![0xab, 0xcd, 0xef]),
234 },
235 ]),
236 }],
237 });
238
239 #[test]
240 fn test_deser() {
241 let res = OtpImg::from_str(TEST_OTP_JSON).unwrap();
242 assert_eq!(res, *TEST_OTP);
243 }
244
245 #[test]
246 fn test_ser() {
247 let json = serialize(&*TEST_OTP).unwrap().to_hjson().to_string();
248 let json_str = "{
249 partitions: [
250 {
251 name: \"CREATOR_SW_CFG\",
252 items: [
253 {
254 name: \"CREATOR_SW_CFG_DIGEST\",
255 value: 0
256 },
257 {
258 name: \"CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN\",
259 value: \"5425512962855773605\"
260 },
261 {
262 name: \"CREATOR_RANDOM\",
263 value: \"<random>\"
264 },
265 {
266 name: \"CREATOR_SEQ\",
267 value: [
268 171,
269 205,
270 239
271 ]
272 }
273 ]
274 }
275 ]
276}";
277 assert_eq!(json_str, json);
278 }
279
280 #[test]
281 fn test_otp_read() {
282 let otp = OtpImg::from_str(TEST_OTP_JSON).unwrap();
283 assert_eq!(otp.read32("CREATOR_SW_CFG_DIGEST").unwrap(), 0x0);
284 assert_eq!(
285 otp.read32("CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN").unwrap(),
286 0x4b4ba5a5
287 );
288 assert_eq!(
289 otp.read32_offset("CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN", 4)
290 .unwrap(),
291 0x4b4b4b4b
292 );
293 assert!(otp.read32("CREATOR_RANDOM").is_err());
294 assert_eq!(otp.read32_offset("CREATOR_SEQ", 0).unwrap(), 0xab);
295 assert_eq!(otp.read32_offset("CREATOR_SEQ", 4).unwrap(), 0xcd);
296 assert_eq!(otp.read32_offset("CREATOR_SEQ", 8).unwrap(), 0xef);
297 }
298}