opentitanlib/ownership/
isfb.rs1use anyhow::Result;
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use serde::Deserialize;
8use serde_annotate::Annotate;
9use std::io::{Read, Write};
10
11use super::GlobalFlags;
12use super::application_key::ApplicationKeyDomain;
13use super::misc::{TlvHeader, TlvTag};
14
15#[derive(Debug, Deserialize, Annotate)]
18pub struct OwnerIsfbConfig {
19 #[serde(
21 skip_serializing_if = "GlobalFlags::not_debug",
22 default = "OwnerIsfbConfig::default_header"
23 )]
24 pub header: TlvHeader,
25 pub bank: u8,
27 pub page: u8,
29 #[serde(default, skip_serializing_if = "GlobalFlags::not_debug")]
31 #[annotate(format=hex)]
32 pub pad: u16,
33
34 #[annotate(format=hex)]
36 pub erase_conditions: u32,
37 #[annotate(format=hex)]
39 pub key_domain: ApplicationKeyDomain,
40 #[serde(default, skip_serializing_if = "GlobalFlags::not_debug")]
42 #[annotate(format=hex)]
43 pub reserved: [u32; 5],
44 pub product_words: u32,
47}
48
49impl Default for OwnerIsfbConfig {
50 fn default() -> Self {
51 Self {
52 header: Self::default_header(),
53 bank: 0u8,
54 page: 0u8,
55 pad: 0u16,
56 erase_conditions: 0u32,
57 key_domain: ApplicationKeyDomain::default(),
58 reserved: [0u32; 5],
59 product_words: 0u32,
60 }
61 }
62}
63
64impl OwnerIsfbConfig {
65 const SIZE: usize = 44;
66 pub fn default_header() -> TlvHeader {
67 TlvHeader::new(TlvTag::IntegratorSpecificFirmwareBinding, Self::SIZE, "0.0")
68 }
69 pub fn read(src: &mut impl Read, header: TlvHeader) -> Result<Self> {
70 let bank = src.read_u8()?;
71 let page = src.read_u8()?;
72 let pad = src.read_u16::<LittleEndian>()?;
73 let erase_conditions = src.read_u32::<LittleEndian>()?;
74 let key_domain = ApplicationKeyDomain(src.read_u32::<LittleEndian>()?);
75 let mut reserved = [0u32; 5];
76 src.read_u32_into::<LittleEndian>(&mut reserved)?;
77 let product_words = src.read_u32::<LittleEndian>()?;
78 Ok(Self {
79 header,
80 bank,
81 page,
82 pad,
83 erase_conditions,
84 key_domain,
85 reserved,
86 product_words,
87 })
88 }
89 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
90 let header = Self::default_header();
91 header.write(dest)?;
92
93 dest.write_u8(self.bank)?;
94 dest.write_u8(self.page)?;
95 dest.write_u16::<LittleEndian>(self.pad)?;
96 dest.write_u32::<LittleEndian>(self.erase_conditions)?;
97 dest.write_u32::<LittleEndian>(u32::from(self.key_domain))?;
98 for x in &self.reserved {
99 dest.write_u32::<LittleEndian>(*x)?;
100 }
101 dest.write_u32::<LittleEndian>(self.product_words)?;
102 Ok(())
103 }
104}
105
106#[cfg(test)]
107mod test {
108 use super::*;
109 use crate::util::hexdump::{hexdump_parse, hexdump_string};
110
111 const OWNER_ISFB_CONF: &str = "\
11200000000: 49 53 46 42 2c 00 00 00 01 08 00 00 66 06 00 00 ISFB,.......f...
11300000010: 70 72 6f 64 00 00 00 00 00 00 00 00 00 00 00 00 prod............
11400000020: 00 00 00 00 00 00 00 00 80 00 00 00 ............
115";
116 const OWNER_ISFB_CONF_JSON: &str = r#"{
117 bank: 1,
118 page: 8,
119 erase_conditions: 0x666,
120 key_domain: "Prod",
121 product_words: 128
122}"#;
123
124 #[test]
125 fn test_owner_isfb_config_write() -> Result<()> {
126 let isfb = OwnerIsfbConfig {
127 header: OwnerIsfbConfig::default_header(),
128 bank: 1,
129 page: 8,
130 pad: 0,
131 erase_conditions: 0x0000_0666,
132 key_domain: ApplicationKeyDomain::Prod,
133 product_words: 128,
134 ..Default::default()
135 };
136
137 let mut bin = Vec::new();
138 isfb.write(&mut bin)?;
139 eprintln!("{}", hexdump_string(&bin)?);
140 assert_eq!(hexdump_string(&bin)?, OWNER_ISFB_CONF);
141 Ok(())
142 }
143
144 #[test]
145 fn test_owner_isfb_config_read() -> Result<()> {
146 let buf = hexdump_parse(OWNER_ISFB_CONF)?;
147 let mut cur = std::io::Cursor::new(&buf);
148 let header = TlvHeader::read(&mut cur)?;
149 let orc = OwnerIsfbConfig::read(&mut cur, header)?;
150 let doc = serde_annotate::serialize(&orc)?.to_json5().to_string();
151 eprintln!("{}", doc);
152 assert_eq!(doc, OWNER_ISFB_CONF_JSON);
153 Ok(())
154 }
155}