opentitanlib/ownership/
flash_info.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, Serialize};
8use serde_annotate::Annotate;
9use std::io::{Read, Write};
10
11use super::GlobalFlags;
12use super::flash::FlashFlags;
13use super::misc::{TlvHeader, TlvTag};
14
15/// Describes an INFO page to which a set of flags apply.
16#[derive(Debug, Default, Deserialize, Serialize, Annotate)]
17pub struct OwnerInfoPage {
18    /// The bank in which the info page resides.
19    pub bank: u8,
20    /// The info page number.
21    pub page: u8,
22    #[serde(default)]
23    #[annotate(format=hex)]
24    pub pad: u16,
25    #[serde(flatten)]
26    pub flags: FlashFlags,
27}
28impl OwnerInfoPage {
29    const SIZE: usize = 12;
30    pub fn new(bank: u8, page: u8, flags: FlashFlags) -> Self {
31        Self {
32            bank,
33            page,
34            flags,
35            ..Default::default()
36        }
37    }
38    pub fn read(src: &mut impl Read, crypt: u64) -> Result<Self> {
39        let bank = src.read_u8()?;
40        let page = src.read_u8()?;
41        let pad = src.read_u16::<LittleEndian>()?;
42        let flags = FlashFlags::from(src.read_u64::<LittleEndian>()? ^ crypt);
43        Ok(Self {
44            bank,
45            page,
46            pad,
47            flags,
48        })
49    }
50    pub fn write(&self, dest: &mut impl Write, crypt: u64) -> Result<()> {
51        dest.write_u8(self.bank)?;
52        dest.write_u8(self.page)?;
53        dest.write_u16::<LittleEndian>(self.pad)?;
54        dest.write_u64::<LittleEndian>(u64::from(self.flags) ^ crypt)?;
55        Ok(())
56    }
57}
58
59/// Describes the overall flash configuration for owner-accesssable INFO pages.
60#[derive(Debug, Serialize, Deserialize, Annotate)]
61pub struct OwnerFlashInfoConfig {
62    /// Header identifying this struct.
63    #[serde(
64        skip_serializing_if = "GlobalFlags::not_debug",
65        default = "OwnerFlashInfoConfig::default_header"
66    )]
67    pub header: TlvHeader,
68    /// A list of info page configurations.
69    pub config: Vec<OwnerInfoPage>,
70}
71
72impl Default for OwnerFlashInfoConfig {
73    fn default() -> Self {
74        Self {
75            header: Self::default_header(),
76            config: Vec::new(),
77        }
78    }
79}
80
81impl OwnerFlashInfoConfig {
82    const BASE_SIZE: usize = 8;
83
84    pub fn default_header() -> TlvHeader {
85        TlvHeader::new(TlvTag::FlashInfoConfig, 0, "0.0")
86    }
87
88    pub fn basic() -> Self {
89        Self {
90            header: TlvHeader::new(TlvTag::FlashInfoConfig, 0, "0.0"),
91            config: vec![
92                OwnerInfoPage::new(0, 6, FlashFlags::info_page()),
93                OwnerInfoPage::new(0, 7, FlashFlags::info_page()),
94                OwnerInfoPage::new(0, 8, FlashFlags::info_page()),
95                OwnerInfoPage::new(0, 9, FlashFlags::info_page()),
96            ],
97        }
98    }
99
100    pub fn read(src: &mut impl Read, header: TlvHeader) -> Result<Self> {
101        let config_len = (header.length - Self::BASE_SIZE) / OwnerInfoPage::SIZE;
102        let mut config = Vec::new();
103        for i in 0..config_len {
104            let crypt = 0x1111_1111_1111_1111u64 * (i as u64);
105            config.push(OwnerInfoPage::read(src, crypt)?)
106        }
107        Ok(Self { header, config })
108    }
109    pub fn write(&self, dest: &mut impl Write) -> Result<()> {
110        let header = TlvHeader::new(
111            TlvTag::FlashInfoConfig,
112            Self::BASE_SIZE + self.config.len() * OwnerInfoPage::SIZE,
113            "0.0",
114        );
115        header.write(dest)?;
116        for (i, config) in self.config.iter().enumerate() {
117            let crypt = 0x1111_1111_1111_1111u64 * (i as u64);
118            config.write(dest, crypt)?;
119        }
120        Ok(())
121    }
122}
123
124#[cfg(test)]
125mod test {
126    use super::*;
127    use crate::util::hexdump::{hexdump_parse, hexdump_string};
128
129    #[rustfmt::skip]
130    const OWNER_FLASH_INFO_CONFIG_BIN: &str =
131r#"00000000: 49 4e 46 4f 2c 00 00 00 00 00 00 00 96 09 00 99  INFO,...........
13200000010: 69 09 00 00 01 02 00 00 77 18 11 88 88 18 11 11  i.......w.......
13300000020: 01 05 00 00 44 24 22 bb 44 24 22 22              ....D$".D$""
134"#;
135
136    const OWNER_FLASH_INFO_CONFIG_JSON: &str = r#"{
137  config: [
138    {
139      bank: 0,
140      page: 0,
141      pad: 0,
142      read: true,
143      program: false,
144      erase: false,
145      scramble: false,
146      ecc: true,
147      high_endurance: false,
148      protect_when_active: false,
149      lock: false
150    },
151    {
152      bank: 1,
153      page: 2,
154      pad: 0,
155      read: true,
156      program: true,
157      erase: false,
158      scramble: false,
159      ecc: false,
160      high_endurance: false,
161      protect_when_active: false,
162      lock: false
163    },
164    {
165      bank: 1,
166      page: 5,
167      pad: 0,
168      read: true,
169      program: true,
170      erase: true,
171      scramble: true,
172      ecc: true,
173      high_endurance: true,
174      protect_when_active: false,
175      lock: false
176    }
177  ]
178}"#;
179
180    #[test]
181    fn test_owner_flash_info_config_write() -> Result<()> {
182        let ofic = OwnerFlashInfoConfig {
183            header: TlvHeader::default(),
184            config: vec![
185                OwnerInfoPage::new(
186                    0,
187                    0,
188                    FlashFlags {
189                        read: true,
190                        ecc: true,
191                        ..Default::default()
192                    },
193                ),
194                OwnerInfoPage::new(
195                    1,
196                    2,
197                    FlashFlags {
198                        read: true,
199                        program: true,
200                        ..Default::default()
201                    },
202                ),
203                OwnerInfoPage::new(1, 5, FlashFlags::basic()),
204            ],
205        };
206        let mut bin = Vec::new();
207        ofic.write(&mut bin)?;
208        eprintln!("{}", hexdump_string(&bin)?);
209        assert_eq!(hexdump_string(&bin)?, OWNER_FLASH_INFO_CONFIG_BIN);
210        Ok(())
211    }
212
213    #[test]
214    fn test_owner_flash_info_confg_read() -> Result<()> {
215        let buf = hexdump_parse(OWNER_FLASH_INFO_CONFIG_BIN)?;
216        let mut cur = std::io::Cursor::new(&buf);
217        let header = TlvHeader::read(&mut cur)?;
218        let orc = OwnerFlashInfoConfig::read(&mut cur, header)?;
219        let doc = serde_annotate::serialize(&orc)?.to_json5().to_string();
220        assert_eq!(doc, OWNER_FLASH_INFO_CONFIG_JSON);
221        Ok(())
222    }
223}