1use anyhow::Result;
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use serde::Deserialize;
8use serde_annotate::Annotate;
9use std::io::{Read, Write};
10
11use ot_hal::util::multibits::MultiBitBool4;
12
13use super::GlobalFlags;
14use super::misc::{TlvHeader, TlvTag};
15
16#[derive(Debug, Default, Clone, Copy, Deserialize, Annotate)]
18pub struct FlashFlags {
19 #[serde(default)]
21 pub read: bool,
22 #[serde(default)]
24 pub program: bool,
25 #[serde(default)]
27 pub erase: bool,
28 #[serde(default)]
30 pub scramble: bool,
31 #[serde(default)]
33 pub ecc: bool,
34 #[serde(default)]
36 pub high_endurance: bool,
37 #[serde(default)]
39 pub protect_when_active: bool,
40 #[serde(default)]
42 pub lock: bool,
43}
44
45impl FlashFlags {
46 const TRUE: u64 = MultiBitBool4::True.0 as u64;
47 const FALSE: u64 = MultiBitBool4::False.0 as u64;
48
49 pub fn basic() -> Self {
51 FlashFlags {
52 read: true,
53 program: true,
54 erase: true,
55 scramble: true,
56 ecc: true,
57 high_endurance: true,
58 ..Default::default()
59 }
60 }
61
62 pub fn rom_ext() -> Self {
64 Self {
65 read: true,
66 program: true,
67 erase: true,
68 protect_when_active: true,
69 ..Default::default()
70 }
71 }
72
73 pub fn firmware() -> Self {
75 Self {
76 read: true,
77 program: true,
78 erase: true,
79 scramble: true,
80 ecc: true,
81 protect_when_active: true,
82 ..Default::default()
83 }
84 }
85
86 pub fn filesystem() -> Self {
88 Self {
89 read: true,
90 program: true,
91 erase: true,
92 high_endurance: true,
93 ..Default::default()
94 }
95 }
96
97 pub fn info_page() -> Self {
99 Self {
100 read: true,
101 program: true,
102 erase: true,
103 scramble: true,
104 ecc: true,
105 ..Default::default()
106 }
107 }
108}
109
110impl From<u64> for FlashFlags {
111 fn from(flags: u64) -> Self {
112 #[rustfmt::skip]
113 let value = Self {
114 read: flags & 0xF == Self::TRUE,
116 program: (flags >> 4) & 0xF == Self::TRUE,
117 erase: (flags >> 8) & 0xF == Self::TRUE,
118 protect_when_active: (flags >> 24) & 0xF == Self::TRUE,
119 lock: (flags >> 28) & 0xF == Self::TRUE,
120
121 scramble: (flags >> 32) & 0xF == Self::TRUE,
123 ecc: (flags >> 36) & 0xF == Self::TRUE,
124 high_endurance: (flags >> 40) & 0xF == Self::TRUE,
125 };
126 value
127 }
128}
129
130impl From<FlashFlags> for u64 {
131 fn from(flags: FlashFlags) -> u64 {
132 #[rustfmt::skip]
133 let value =
134 if flags.read { FlashFlags::TRUE } else { FlashFlags::FALSE } |
136 if flags.program { FlashFlags::TRUE } else { FlashFlags::FALSE } << 4 |
137 if flags.erase { FlashFlags::TRUE } else { FlashFlags::FALSE } << 8 |
138 if flags.protect_when_active { FlashFlags::TRUE } else { FlashFlags::FALSE } << 24 |
139 if flags.lock { FlashFlags::TRUE } else { FlashFlags::FALSE } << 28 |
140
141 if flags.scramble { FlashFlags::TRUE } else { FlashFlags::FALSE } << 32 |
143 if flags.ecc { FlashFlags::TRUE } else { FlashFlags::FALSE } << 36 |
144 if flags.high_endurance { FlashFlags::TRUE } else { FlashFlags::FALSE } << 40 ;
145 value
146 }
147}
148
149#[derive(Debug, Default, Deserialize, Annotate)]
151pub struct OwnerFlashRegion {
152 pub start: u16,
154 pub size: u16,
156 #[serde(flatten)]
157 pub flags: FlashFlags,
158}
159
160impl OwnerFlashRegion {
161 const SIZE: usize = 12;
162 pub fn new(start: u16, size: u16, flags: FlashFlags) -> Self {
163 Self { start, size, flags }
164 }
165 pub fn read(src: &mut impl Read, crypt: u64) -> Result<Self> {
166 let start = src.read_u16::<LittleEndian>()?;
167 let size = src.read_u16::<LittleEndian>()?;
168 let flags = FlashFlags::from(src.read_u64::<LittleEndian>()? ^ crypt);
169 Ok(Self { start, size, flags })
170 }
171 pub fn write(&self, dest: &mut impl Write, crypt: u64) -> Result<()> {
172 dest.write_u16::<LittleEndian>(self.start)?;
173 dest.write_u16::<LittleEndian>(self.size)?;
174 dest.write_u64::<LittleEndian>(u64::from(self.flags) ^ crypt)?;
175 Ok(())
176 }
177}
178
179#[derive(Debug, Deserialize, Annotate)]
181pub struct OwnerFlashConfig {
182 #[serde(
184 skip_serializing_if = "GlobalFlags::not_debug",
185 default = "OwnerFlashConfig::default_header"
186 )]
187 pub header: TlvHeader,
188 pub config: Vec<OwnerFlashRegion>,
190}
191
192impl Default for OwnerFlashConfig {
193 fn default() -> Self {
194 Self {
195 header: Self::default_header(),
196 config: Vec::new(),
197 }
198 }
199}
200
201impl OwnerFlashConfig {
202 const BASE_SIZE: usize = 8;
203
204 pub fn default_header() -> TlvHeader {
205 TlvHeader::new(TlvTag::FlashConfig, 0, "0.0")
206 }
207 pub fn basic() -> Self {
208 Self {
209 header: TlvHeader::new(TlvTag::FlashConfig, 0, "0.0"),
210 config: vec![
211 OwnerFlashRegion::new(0, 32, FlashFlags::rom_ext()),
212 OwnerFlashRegion::new(32, 192, FlashFlags::firmware()),
213 OwnerFlashRegion::new(224, 32, FlashFlags::filesystem()),
214 OwnerFlashRegion::new(256, 32, FlashFlags::rom_ext()),
215 OwnerFlashRegion::new(256 + 32, 192, FlashFlags::firmware()),
216 OwnerFlashRegion::new(256 + 224, 32, FlashFlags::filesystem()),
217 ],
218 }
219 }
220 pub fn read(src: &mut impl Read, header: TlvHeader) -> Result<Self> {
221 let config_len = (header.length - Self::BASE_SIZE) / OwnerFlashRegion::SIZE;
222 let mut config = Vec::new();
223 for i in 0..config_len {
224 let crypt = 0x1111_1111_1111_1111u64 * (i as u64);
225 config.push(OwnerFlashRegion::read(src, crypt)?)
226 }
227 Ok(Self { header, config })
228 }
229 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
230 let header = TlvHeader::new(
231 TlvTag::FlashConfig,
232 Self::BASE_SIZE + self.config.len() * OwnerFlashRegion::SIZE,
233 "0.0",
234 );
235 header.write(dest)?;
236 for (i, config) in self.config.iter().enumerate() {
237 let crypt = 0x1111_1111_1111_1111u64 * (i as u64);
238 config.write(dest, crypt)?;
239 }
240 Ok(())
241 }
242}
243
244#[cfg(test)]
245mod test {
246 use super::*;
247 use crate::util::hexdump::{hexdump_parse, hexdump_string};
248
249 #[rustfmt::skip]
250 const OWNER_FLASH_CONFIG_BIN: &str =
251r#"00000000: 46 4c 53 48 2c 00 00 00 00 00 00 00 96 09 00 99 FLSH,...........
25200000010: 69 09 00 00 01 00 02 00 77 18 11 88 88 18 11 11 i.......w.......
25300000020: 03 00 05 00 44 24 22 bb 44 24 22 22 ....D$".D$""
254"#;
255
256 const OWNER_FLASH_CONFIG_JSON: &str = r#"{
257 config: [
258 {
259 start: 0,
260 size: 0,
261 read: true,
262 program: false,
263 erase: false,
264 scramble: false,
265 ecc: true,
266 high_endurance: false,
267 protect_when_active: false,
268 lock: false
269 },
270 {
271 start: 1,
272 size: 2,
273 read: true,
274 program: true,
275 erase: false,
276 scramble: false,
277 ecc: false,
278 high_endurance: false,
279 protect_when_active: false,
280 lock: false
281 },
282 {
283 start: 3,
284 size: 5,
285 read: true,
286 program: true,
287 erase: true,
288 scramble: true,
289 ecc: true,
290 high_endurance: true,
291 protect_when_active: false,
292 lock: false
293 }
294 ]
295}"#;
296
297 #[test]
298 fn test_owner_flash_config_write() -> Result<()> {
299 let ofr = OwnerFlashConfig {
300 header: TlvHeader::default(),
301 config: vec![
302 OwnerFlashRegion::new(
303 0,
304 0,
305 FlashFlags {
306 read: true,
307 ecc: true,
308 ..Default::default()
309 },
310 ),
311 OwnerFlashRegion::new(
312 1,
313 2,
314 FlashFlags {
315 read: true,
316 program: true,
317 ..Default::default()
318 },
319 ),
320 OwnerFlashRegion::new(3, 5, FlashFlags::basic()),
321 ],
322 };
323 let mut bin = Vec::new();
324 ofr.write(&mut bin)?;
325 eprintln!("{}", hexdump_string(&bin)?);
326 assert_eq!(hexdump_string(&bin)?, OWNER_FLASH_CONFIG_BIN);
327 Ok(())
328 }
329
330 #[test]
331 fn test_owner_flash_config_read() -> Result<()> {
332 let buf = hexdump_parse(OWNER_FLASH_CONFIG_BIN)?;
333 let mut cur = std::io::Cursor::new(&buf);
334 let header = TlvHeader::read(&mut cur)?;
335 let ofr = OwnerFlashConfig::read(&mut cur, header)?;
336 let doc = serde_annotate::serialize(&ofr)?.to_json5().to_string();
337 assert_eq!(doc, OWNER_FLASH_CONFIG_JSON);
338 Ok(())
339 }
340}