opentitanlib/chip/
boot_log.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};
7use serde::Serialize;
8use serde_annotate::Annotate;
9use sha2::{Digest, Sha256};
10use std::convert::TryFrom;
11
12use super::ChipDataError;
13use super::boot_svc::BootSlot;
14use crate::with_unknown;
15
16with_unknown! {
17    pub enum OwnershipState: u32 [default = Self::Recovery] {
18        Recovery = 0,
19        LockedOwner = 0x444e574f,
20        UnlockedSelf = 0x464c5355,
21        UnlockedAny = 0x594e4155,
22        UnlockedEndorsed = 0x444e4555,
23    }
24
25}
26
27/// The BootLog provides information about how the ROM and ROM_EXT
28/// booted the chip.
29#[derive(Debug, Default, Serialize, Annotate)]
30pub struct BootLog {
31    /// A SHA256 digest over all other fields in this struct.
32    #[annotate(format=hex)]
33    pub digest: [u32; 8],
34    /// A tag that identifies this struct as the boot log ('BLOG').
35    #[annotate(format=hex)]
36    pub identifier: u32,
37    /// The chip version (a git hash prefix from the ROM).
38    #[annotate(format=hex)]
39    pub chip_version: u64,
40    /// The boot slot the ROM chose to boot the ROM_EXT.
41    pub rom_ext_slot: BootSlot,
42    /// The ROM_EXT major version number.
43    pub rom_ext_major: u32,
44    /// The ROM_EXT minor version number.
45    pub rom_ext_minor: u32,
46    /// The ROM_EXT size in bytes.
47    #[annotate(format=hex)]
48    pub rom_ext_size: u32,
49    /// The ROM_EXT nonce (a value used to prevent replay of signed commands).
50    #[annotate(format=hex)]
51    pub rom_ext_nonce: u64,
52    /// The boot slot the ROM_EXT chose to boot the owner firmware.
53    pub bl0_slot: BootSlot,
54    /// The chip's ownership state.
55    pub ownership_state: OwnershipState,
56    /// Reserved for future use.
57    #[annotate(format=hex)]
58    pub reserved: [u32; 13],
59}
60
61impl TryFrom<&[u8]> for BootLog {
62    type Error = ChipDataError;
63    fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
64        if buf.len() < Self::SIZE {
65            return Err(ChipDataError::BadSize(Self::SIZE, buf.len()));
66        }
67        if !BootLog::valid_digest(buf) {
68            return Err(ChipDataError::InvalidDigest);
69        }
70        let mut reader = std::io::Cursor::new(buf);
71        let mut val = BootLog::default();
72        reader.read_u32_into::<LittleEndian>(&mut val.digest)?;
73        val.identifier = reader.read_u32::<LittleEndian>()?;
74        val.chip_version = reader.read_u64::<LittleEndian>()?;
75        val.rom_ext_slot = BootSlot(reader.read_u32::<LittleEndian>()?);
76        val.rom_ext_major = reader.read_u32::<LittleEndian>()?;
77        val.rom_ext_minor = reader.read_u32::<LittleEndian>()?;
78        val.rom_ext_size = reader.read_u32::<LittleEndian>()?;
79        val.rom_ext_nonce = reader.read_u64::<LittleEndian>()?;
80        val.bl0_slot = BootSlot(reader.read_u32::<LittleEndian>()?);
81        val.ownership_state = OwnershipState(reader.read_u32::<LittleEndian>()?);
82        reader.read_u32_into::<LittleEndian>(&mut val.reserved)?;
83        Ok(val)
84    }
85}
86
87impl BootLog {
88    pub const SIZE: usize = 128;
89    const HASH_LEN: usize = 32;
90
91    fn valid_digest(buf: &[u8]) -> bool {
92        let mut digest = Sha256::digest(&buf[Self::HASH_LEN..Self::SIZE]);
93        digest.reverse();
94        digest[..] == buf[..Self::HASH_LEN]
95    }
96}