| // Licensed under the Apache-2.0 license |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| //! Boot Log structures for OpenTitan. |
| //! |
| //! The `BootLog` is populated by early boot stages (ROM and ROM_EXT) to describe |
| //! the boot process, including slot choices, versions, sizes, and ownership |
| //! states of the loaded stages. This log is passed to the application via |
| //! the Retention SRAM (`RetRam.boot_log` field). |
| |
| use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; |
| |
| use crate::misc::UnalignedU64; |
| use crate::tags::{BootSlot, HardenedBool, OwnershipState}; |
| use crate::CheckDigest; |
| |
| /// Information about the boot flow generated by ROM and ROM_EXT. |
| /// |
| /// It contains hashes, slot selections, version information, and security levels |
| /// of the boot components. The entire structure is protected by an integrity digest. |
| #[derive(Clone, FromBytes, Immutable, IntoBytes, KnownLayout)] |
| #[repr(C)] |
| pub struct BootLog { |
| /// A SHA256 integrity digest computed over all subsequent fields in this structure. |
| pub digest: [u8; 32], |
| /// A tag identifying this structure. Must be `'BLOG'`. |
| pub identifier: u32, |
| /// The hardware/ROM version (typically a Git commit hash prefix). |
| pub chip_version: UnalignedU64, |
| /// The boot slot chosen by the ROM to run the ROM Extension (ROM_EXT). |
| pub rom_ext_slot: BootSlot, |
| /// ROM_EXT major version. |
| pub rom_ext_major: u32, |
| /// ROM_EXT minor version. |
| pub rom_ext_minor: u32, |
| /// ROM_EXT size in bytes. |
| pub rom_ext_size: u32, |
| /// Anti-replay nonce value used by ROM_EXT. |
| pub rom_ext_nonce: UnalignedU64, |
| /// The boot slot chosen by the ROM_EXT to run the owner application (BL0). |
| pub bl0_slot: BootSlot, |
| /// The chip's ownership state at boot time. |
| pub ownership_state: OwnershipState, |
| /// Cumulative counter of ownership transfers performed on this chip. |
| pub ownership_transfers: u32, |
| /// Minimum security version permitted for ROM_EXT images. |
| pub rom_ext_min_sec_ver: u32, |
| /// Minimum security version permitted for owner application (BL0) images. |
| pub bl0_min_sec_ver: u32, |
| /// The primary BL0 boot slot configured in the chip. |
| pub primary_bl0_slot: BootSlot, |
| /// Hardened boolean indicating if the retention RAM was freshly initialized. |
| pub retention_ram_initialized: HardenedBool, |
| /// Reserved space for future extensions. |
| pub reserved: [u32; 8], |
| } |
| |
| impl CheckDigest for BootLog { |
| /// Validates the integrity digest of the `BootLog`. |
| /// |
| /// The digest is calculated over the structure bytes starting immediately |
| /// after the `digest` field (byte offset 32). |
| fn check_digest<F>(&self, f: F) -> bool |
| where |
| F: Fn(&[u8]) -> [u8; 32], |
| { |
| let digest = f(&self.as_bytes()[32..]); |
| // OpenTitan digests are stored in reverse byte order |
| for (a, b) in self.digest.iter().zip(digest.iter().rev()) { |
| if *a != *b { |
| return false; |
| } |
| } |
| true |
| } |
| |
| /// Computes and sets the integrity digest on the `BootLog`. |
| fn set_digest<F>(&mut self, f: F) |
| where |
| F: Fn(&[u8]) -> [u8; 32], |
| { |
| let digest = f(&self.as_bytes()[32..]); |
| for (a, b) in self.digest.iter_mut().zip(digest.iter().rev()) { |
| *a = *b; |
| } |
| } |
| } |