opentitanlib/ownership/
isfb.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use 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/// The owner Integration Specific Firmware Binding (ISFB) configuration
16/// describes the configuration parameters for the ISFB region.
17#[derive(Debug, Deserialize, Annotate)]
18pub struct OwnerIsfbConfig {
19    /// Header identifying this struct.
20    #[serde(
21        skip_serializing_if = "GlobalFlags::not_debug",
22        default = "OwnerIsfbConfig::default_header"
23    )]
24    pub header: TlvHeader,
25    /// The flash bank where the ISFB is located.
26    pub bank: u8,
27    /// The info flash page where the ISFB is located.
28    pub page: u8,
29    /// Padding for alignment.
30    #[serde(default, skip_serializing_if = "GlobalFlags::not_debug")]
31    #[annotate(format=hex)]
32    pub pad: u16,
33
34    /// The erase policy for the ISFB region.
35    #[annotate(format=hex)]
36    pub erase_conditions: u32,
37    /// The key domain associated with the erase condition policy.
38    #[annotate(format=hex)]
39    pub key_domain: ApplicationKeyDomain,
40    /// Reserved for future use.
41    #[serde(default, skip_serializing_if = "GlobalFlags::not_debug")]
42    #[annotate(format=hex)]
43    pub reserved: [u32; 5],
44    /// Number of `uint32_t` reserved for product expressions. It has to be a
45    /// value less than or equal to 256.
46    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}