| // Licensed under the Apache-2.0 license |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| //! Internal context structures for HACE hashing. |
| |
| use core::cell::UnsafeCell; |
| |
| pub(crate) const SHA256_DIGEST_SIZE: usize = 32; |
| pub(crate) const SHA384_DIGEST_SIZE: usize = 48; |
| pub(crate) const SHA512_DIGEST_SIZE: usize = 64; |
| /// Block size for SHA-1/224/256. |
| pub(crate) const HACE_BLOCK_SIZE: usize = 64; |
| /// Block size for SHA-384/512. |
| pub(crate) const HACE_BLOCK_SIZE_128: usize = 128; |
| pub(crate) const HACE_BUFFER_SIZE: usize = 256; |
| |
| pub(crate) const SHA256_IV: [u32; 8] = [ |
| 0x67e6_096a, |
| 0x85ae_67bb, |
| 0x72f3_6e3c, |
| 0x3af5_4fa5, |
| 0x7f52_0e51, |
| 0x8c68_059b, |
| 0xabd9_831f, |
| 0x19cd_e05b, |
| ]; |
| |
| /// SHA-384 IV, verbatim from the pinned Zephyr `hash_aspeed_priv.h` (`sha384_iv`). |
| pub(crate) const SHA384_IV: [u32; 16] = [ |
| 0x5d9d_bbcb, |
| 0xd89e_05c1, |
| 0x2a29_9a62, |
| 0x07d5_7c36, |
| 0x5a01_5991, |
| 0x17dd_7030, |
| 0xd8ec_2f15, |
| 0x3959_0ef7, |
| 0x6726_3367, |
| 0x310b_c0ff, |
| 0x874a_b48e, |
| 0x1115_5868, |
| 0x0d2e_0cdb, |
| 0xa78f_f964, |
| 0x1d48_b547, |
| 0xa44f_fabe, |
| ]; |
| |
| /// SHA-512 IV, verbatim from the pinned Zephyr `hash_aspeed_priv.h` (`sha512_iv`). |
| pub(crate) const SHA512_IV: [u32; 16] = [ |
| 0x67e6_096a, |
| 0x08c9_bcf3, |
| 0x85ae_67bb, |
| 0x3ba7_ca84, |
| 0x72f3_6e3c, |
| 0x2bf8_94fe, |
| 0x3af5_4fa5, |
| 0xf136_1d5f, |
| 0x7f52_0e51, |
| 0xd182_e6ad, |
| 0x8c68_059b, |
| 0x1f6c_3e2b, |
| 0xabd9_831f, |
| 0x6bbd_41fb, |
| 0x19cd_e05b, |
| 0x7921_7e13, |
| ]; |
| |
| pub(crate) const DIGEST_BUFFER_SIZE: usize = 64; |
| pub(crate) const KEY_BUFFER_SIZE: usize = 128; |
| |
| #[derive(Copy, Clone)] |
| #[repr(C)] |
| pub(crate) struct Sg { |
| /// Byte length of the buffer, OR'd with `HACE_SG_LAST` (bit 31) for the |
| /// final/only entry in the scatter-gather list. Hardware SG format has |
| /// `len` at offset +0, `addr` at offset +4 — matches both the pinned |
| /// Zephyr `aspeed_sg` struct (`hace_aspeed.h`) and `aspeed-rust` |
| /// `AspeedSg { len, addr }`. HACE parses len @ +0, addr @ +4. |
| pub(crate) len: u32, |
| /// Physical address of the data buffer. |
| pub(crate) addr: u32, |
| } |
| |
| impl Sg { |
| pub const fn new() -> Self { |
| Self { len: 0, addr: 0 } |
| } |
| } |
| |
| #[repr(C, align(64))] |
| pub(crate) struct HashContext { |
| pub(crate) sg: [Sg; 2], |
| pub(crate) digest: [u8; DIGEST_BUFFER_SIZE], |
| pub(crate) method: u32, |
| pub(crate) block_size: u32, |
| pub(crate) key: [u8; KEY_BUFFER_SIZE], |
| pub(crate) key_len: u32, |
| pub(crate) ipad: [u8; KEY_BUFFER_SIZE], |
| pub(crate) opad: [u8; KEY_BUFFER_SIZE], |
| pub(crate) digcnt: [u64; 2], |
| pub(crate) bufcnt: u32, |
| pub(crate) buffer: [u8; HACE_BUFFER_SIZE], |
| pub(crate) iv_size: u8, |
| } |
| |
| impl HashContext { |
| pub const fn new() -> Self { |
| Self { |
| sg: [Sg::new(), Sg::new()], |
| digest: [0; DIGEST_BUFFER_SIZE], |
| method: 0, |
| block_size: 0, |
| key: [0; KEY_BUFFER_SIZE], |
| key_len: 0, |
| ipad: [0; KEY_BUFFER_SIZE], |
| opad: [0; KEY_BUFFER_SIZE], |
| digcnt: [0; 2], |
| bufcnt: 0, |
| buffer: [0; HACE_BUFFER_SIZE], |
| iv_size: 0, |
| } |
| } |
| } |
| |
| #[allow(dead_code)] |
| pub(crate) struct SectionPlacedContext(UnsafeCell<HashContext>); |
| |
| // SAFETY: HACE is owned by a single-threaded driver; access is serialized by the caller. |
| unsafe impl Sync for SectionPlacedContext {} |
| |
| impl SectionPlacedContext { |
| pub const fn new() -> Self { |
| Self(UnsafeCell::new(HashContext::new())) |
| } |
| |
| pub fn get(&self) -> *mut HashContext { |
| self.0.get() |
| } |
| } |
| |
| #[unsafe(link_section = ".ram_nc")] |
| static SHARED_HASH_CTX: SectionPlacedContext = SectionPlacedContext::new(); |
| |
| /// Acquire the raw pointer to the section-placed hash context, to be held as |
| /// private state by the one [`HaceDevice`](super::device::HaceDevice). |
| /// |
| /// This is the *only* path to the context. There is deliberately no free |
| /// accessor that hands the pointer to arbitrary call sites: the operation |
| /// state is reached exclusively *through* the borrowed device (every |
| /// `HaceDigest`/`HaceHmac` reborrows it under the device's `&mut`), which is |
| /// what makes engine exclusivity borrow-arbitrated rather than caller |
| /// discipline (`design-patterns` :: `borrow-arbitrated-engine-exclusivity`, |
| /// Checklist box 2). |
| /// |
| /// The context must remain a `.ram_nc`, `#[repr(C, align(64))]` static — it |
| /// holds the SG list / `buffer` / `digest` DMA targets and cannot live on a |
| /// stack-placed device value (`goal.md` §1.3/§5.1). That residual static is |
| /// the pattern's stated hardware liability ("language fiction, not a hardware |
| /// lock"); single-instance is gate-delegated to the `unsafe fn new*` contract |
| /// below (Checklist box 3), exactly as the sibling SBC port does. |
| /// |
| /// # Safety |
| /// The HACE engine is a hardware singleton. The caller (the `HaceDevice` |
| /// construction gate) must uphold the same single-instance/non-reentrancy |
| /// contract as `HaceRegisters::new*`: at most one live `HaceDevice`, hence at |
| /// most one live `&mut` minted from this pointer, at a time. |
| pub(crate) unsafe fn acquire_shared_ctx() -> *mut HashContext { |
| SHARED_HASH_CTX.get() |
| } |
| |
| // ----- AES (crypto sub-engine) context ---------------------------------- |
| // |
| // Mirrors the pinned authority `struct aspeed_crypto_ctx` |
| // (`zephyr-reference/crypto_aspeed_priv.h:20-24`; goal.md §1.9.3): a 64-byte |
| // engine context (`ctx[0..16)` = IV for CBC, `ctx[16..]` = raw key), plus the |
| // source/destination SG descriptors and the command word. `ctx`, `src`, `dst` |
| // are DMA targets handed to the engine by physical address — same `.ram_nc`, |
| // `#[repr(C, align(64))]`, single-in-flight discipline (and the same |
| // layout-sensitivity caution, goal.md §2.2) as `HashContext`. |
| |
| #[repr(C, align(64))] |
| pub(crate) struct CryptoContext { |
| /// Engine context buffer: `[0..16)` IV (CBC), `[16..16+keylen)` raw key |
| /// (`hace_aspeed.c:114`, `:186`/`:200`). |
| pub(crate) ctx: [u8; 64], |
| /// Source SG descriptor (`addr` = data, `len = bytes | HACE_SG_LAST`). |
| pub(crate) src: Sg, |
| /// Destination SG descriptor. |
| pub(crate) dst: Sg, |
| } |
| |
| impl CryptoContext { |
| pub const fn new() -> Self { |
| Self { |
| ctx: [0; 64], |
| src: Sg::new(), |
| dst: Sg::new(), |
| } |
| } |
| } |
| |
| #[allow(dead_code)] |
| pub(crate) struct SectionPlacedCrypto(UnsafeCell<CryptoContext>); |
| |
| // SAFETY: HACE is owned by a single-threaded driver; access is serialized by |
| // the caller (the `unsafe fn new*` single-instance contract). |
| unsafe impl Sync for SectionPlacedCrypto {} |
| |
| impl SectionPlacedCrypto { |
| pub const fn new() -> Self { |
| Self(UnsafeCell::new(CryptoContext::new())) |
| } |
| |
| pub fn get(&self) -> *mut CryptoContext { |
| self.0.get() |
| } |
| } |
| |
| #[unsafe(link_section = ".ram_nc")] |
| static SHARED_CRYPTO_CTX: SectionPlacedCrypto = SectionPlacedCrypto::new(); |
| |
| /// Acquire the raw pointer to the section-placed crypto context, held as |
| /// private state by the one [`HaceDevice`](super::device::HaceDevice). Exactly |
| /// the [`acquire_shared_ctx`] discipline, for the AES path: no free accessor; |
| /// the live `&mut` is reached only *through* the borrowed device |
| /// (`borrow-arbitrated-engine-exclusivity`, goal.md §2.3 delta A1). AES is the |
| /// engine's third operation; it shares the same single-in-flight constraint |
| /// (goal.md §5.1) as digest/HMAC. |
| /// |
| /// # Safety |
| /// Same single-instance/non-reentrancy contract as [`acquire_shared_ctx`]: at |
| /// most one live `HaceDevice`, hence at most one live `&mut` from this pointer. |
| pub(crate) unsafe fn acquire_crypto_ctx() -> *mut CryptoContext { |
| SHARED_CRYPTO_CTX.get() |
| } |