Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debug unlock procedures in rom #1851

Open
wants to merge 5 commits into
base: main-2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 109 additions & 0 deletions api/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ impl CommandId {

// The get IDevID ECC CSR command.
pub const GET_IDEV_ECC_CSR: Self = Self(0x4944_4352); // "IDCR"

// Debug unlock commands
pub const MANUF_DEBUG_UNLOCK_REQ_TOKEN: Self = Self(0x4d445554); // "MDUT"
pub const PRODUCTION_AUTH_DEBUG_UNLOCK_REQ: Self = Self(0x50445552); // "PDUR"
pub const PRODUCTION_AUTH_DEBUG_UNLOCK_TOKEN: Self = Self(0x50445554); // "PDUT"
}

impl From<u32> for CommandId {
Expand Down Expand Up @@ -1092,6 +1097,110 @@ pub struct AuthorizeAndStashResp {
}
impl Response for AuthorizeAndStashResp {}

// MANUF_DEBUG_UNLOCK_REQ_TOKEN
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq, Default)]
pub struct ManufDebugUnlockTokenReq {
pub hdr: MailboxReqHeader,
pub token: [u8; 16],
}
impl Request for ManufDebugUnlockTokenReq {
const ID: CommandId = CommandId::MANUF_DEBUG_UNLOCK_REQ_TOKEN;
type Resp = MailboxRespHeader;
}

// PRODUCTION_AUTH_DEBUG_UNLOCK_REQ
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq, Default)]
pub struct ProductionAuthDebugUnlockReq {
pub hdr: MailboxReqHeader,
pub vendor_id: u16, // Vendor ID (2 bytes)
pub object_data_type: u8, // Object Data Type (1 byte)
pub _reserved_1: u8, // Reserved (1 byte)
pub length: [u8; 3], // Length (3 bytes, should be ensured as 3 DWORDs)
pub _reserved_2: u8, // Reserved (1 byte)
pub unlock_category: [u8; 3], // Unlock Category (3 bytes, Bits[0:3] - Debug unlock Level)
pub _reserved_3: u8, // Reserved (1 byte)
}

impl Request for ProductionAuthDebugUnlockReq {
const ID: CommandId = CommandId::PRODUCTION_AUTH_DEBUG_UNLOCK_REQ;
type Resp = ProductionAuthDebugUnlockChallenge;
}

// PRODUCTION_AUTH_DEBUG_UNLOCK_CHALLENGE
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct ProductionAuthDebugUnlockChallenge {
pub hdr: MailboxRespHeader,
pub vendor_id: u16, // Vendor ID (2 bytes)
pub object_data_type: u8, // Object Data Type (1 byte)
pub _reserved_1: u8, // Reserved (1 byte)
pub length: [u8; 3], // Length (3 bytes, should be ensured as 8 (TODO?) DWORDs)
pub _reserved_2: u8, // Reserved (1 byte)
pub unique_device_identifier: [u8; 32], // Device identifier of the Caliptra Device
pub challenge: [u8; 48], // Random number
}
impl Default for ProductionAuthDebugUnlockChallenge {
fn default() -> Self {
Self {
hdr: Default::default(),
vendor_id: Default::default(),
object_data_type: Default::default(),
_reserved_1: Default::default(),
length: Default::default(),
_reserved_2: Default::default(),
unique_device_identifier: Default::default(),
challenge: [0; 48],
}
}
}
impl Response for ProductionAuthDebugUnlockChallenge {}

// PRODUCTION_AUTH_DEBUG_UNLOCK_TOKEN
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct ProductionAuthDebugUnlockToken {
pub hdr: MailboxReqHeader,
pub vendor_id: u16, // Vendor ID (2 bytes)
pub object_data_type: u8, // Object Data Type (1 byte)
pub _reserved_1: u8, // Reserved (1 byte)
pub length: [u8; 3], // Length (3 bytes, should be ensured as 0x754)
pub _reserved_2: u8, // Reserved (1 byte)
pub unique_device_identifier: [u8; 32], // Device identifier of the Caliptra Device
pub unlock_category: [u8; 3], // Unlock Category (3 bytes, Bits[0:3] - Debug unlock Level)
pub _reserved_3: u8, // Reserved (1 byte)
pub challenge: [u8; 48], // Random number
pub ecc_public_key: [u8; 96], // ECC public key
pub mldsa_public_key: [u8; 2592], // MLDSA public key
pub ecc_signature: [u8; 96], // ECC P-384 signature of the Message hashed using SHA2-384. R-Coordinate: Random Point (48 bytes) S-Coordinate: Proof (48 bytes)
pub mldsa_signature: [u8; 4628], // MLDSA signature of the Message hashed using SHA2-512. (4627 bytes + 1 Reserved byte).
}
impl Default for ProductionAuthDebugUnlockToken {
fn default() -> Self {
Self {
hdr: Default::default(),
vendor_id: Default::default(),
object_data_type: Default::default(),
_reserved_1: Default::default(),
length: Default::default(),
_reserved_2: Default::default(),
unique_device_identifier: Default::default(),
unlock_category: Default::default(),
_reserved_3: Default::default(),
challenge: [0; 48],
ecc_public_key: [0; 96],
mldsa_public_key: [0; 2592],
ecc_signature: [0; 96],
mldsa_signature: [0; 4628],
}
}
}
impl Request for ProductionAuthDebugUnlockToken {
const ID: CommandId = CommandId::PRODUCTION_AUTH_DEBUG_UNLOCK_TOKEN; // TODO
type Resp = MailboxRespHeader; // TODO Check
}

/// Retrieves dlen bytes from the mailbox.
pub fn mbox_read_response(
mbox: mbox::RegisterBlock<impl MmioMut>,
Expand Down
3 changes: 3 additions & 0 deletions api/src/soc_mgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ pub trait SocManager {
self.soc_ifc()
.fuse_soc_stepping_id()
.write(|w| w.soc_stepping_id(fuses.soc_stepping_id.into()));
self.soc_ifc()
.fuse_manuf_dbg_unlock_token()
.write(&fuses.manuf_dbg_unlock_token);

self.soc_ifc().cptra_fuse_wr_done().write(|w| w.done(true));

Expand Down
48 changes: 48 additions & 0 deletions api/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub const DEFAULT_CPTRA_OBF_KEY: [u32; 8] = [
0xa0a1a2a3, 0xb0b1b2b3, 0xc0c1c2c3, 0xd0d1d2d3, 0xe0e1e2e3, 0xf0f1f2f3, 0xa4a5a6a7, 0xb4b5b6b7,
];

pub const DEFAULT_MANUF_DEBUG_UNLOCK_TOKEN: [u32; 4] =
[0xcfcecdcc, 0xcbcac9c8, 0xc7c6c5c4, 0xc3c2c1c0];

// Based on device_lifecycle_e from RTL
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum DeviceLifecycle {
Expand Down Expand Up @@ -82,6 +85,49 @@ impl SecurityState {
}
}

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct DbgManufServiceRegReq(u32);
impl From<u32> for DbgManufServiceRegReq {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<DbgManufServiceRegReq> for u32 {
fn from(value: DbgManufServiceRegReq) -> Self {
value.0
}
}

impl DbgManufServiceRegReq {
pub fn set_manuf_dbg_unlock_req(&mut self, val: bool) -> &mut Self {
let mask = 1 << 0;
if val {
self.0 |= mask;
} else {
self.0 &= !mask
};
self
}
pub fn set_prod_dbg_unlock_req(&mut self, val: bool) -> &mut Self {
let mask = 1 << 1;
if val {
self.0 |= mask;
} else {
self.0 &= !mask
};
self
}
pub fn set_uds_program_req(&mut self, val: bool) -> &mut Self {
let mask = 1 << 2;
if val {
self.0 |= mask;
} else {
self.0 &= !mask
};
self
}
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum U4 {
#[default]
Expand Down Expand Up @@ -168,6 +214,7 @@ pub struct Fuses {
pub fuse_lms_revocation: u32,
pub fuse_mldsa_revocation: u32,
pub soc_stepping_id: u16,
pub manuf_dbg_unlock_token: [u32; 4],
}
impl Default for Fuses {
fn default() -> Self {
Expand All @@ -186,6 +233,7 @@ impl Default for Fuses {
fuse_lms_revocation: Default::default(),
fuse_mldsa_revocation: Default::default(),
soc_stepping_id: Default::default(),
manuf_dbg_unlock_token: DEFAULT_MANUF_DEBUG_UNLOCK_TOKEN,
}
}
}
Expand Down
37 changes: 34 additions & 3 deletions drivers/src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use caliptra_registers::axi_dma::{
enums::{RdRouteE, WrRouteE},
AxiDmaReg,
};
use core::ops::Add;
use zerocopy::AsBytes;

pub enum DmaReadTarget {
Expand All @@ -39,6 +40,22 @@ impl From<u64> for AxiAddr {
}
}
}
impl From<AxiAddr> for u64 {
fn from(addr: AxiAddr) -> Self {
(addr.hi as u64) << 32 | (addr.lo as u64)
}
}

impl Add for AxiAddr {
type Output = Self;

fn add(self, rhs: Self) -> Self {
let self_u64: u64 = self.into();
let rhs_u64: u64 = rhs.into();
let sum = self_u64 + rhs_u64;
sum.into()
}
}

pub struct DmaReadTransaction {
pub read_addr: AxiAddr,
Expand Down Expand Up @@ -230,20 +247,34 @@ impl Dma {
/// * `CaliptraResult<u32>` - Read value or error code
pub fn read_dword(&mut self, read_addr: AxiAddr) -> CaliptraResult<u32> {
let mut read_val: u32 = 0;
self.read_buffer(read_addr, read_val.as_bytes_mut())?;
Ok(read_val)
}

/// Read an arbitrary length buffer to fifo and read back the fifo into the provided buffer
///
/// # Arguments
///
/// * `read_addr` - Address to read from
/// * `buffer` - Target location to read to
///
/// # Returns
///
/// * CaliptraResult<()> - Success or failure
pub fn read_buffer(&mut self, read_addr: AxiAddr, buffer: &mut [u8]) -> CaliptraResult<()> {
self.flush();

let read_transaction = DmaReadTransaction {
read_addr,
fixed_addr: false,
length: core::mem::size_of::<u32>() as u32,
length: buffer.len() as u32,
target: DmaReadTarget::AhbFifo,
};

self.setup_dma_read(read_transaction);
self.do_transaction()?;
self.dma_read_fifo(read_val.as_bytes_mut())?;
Ok(read_val)
self.dma_read_fifo(buffer)?;
Ok(())
}

/// Write a 32-bit word to the specified address
Expand Down
15 changes: 14 additions & 1 deletion drivers/src/fuse_bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Abstract:

--*/

use crate::Array4x12;
use crate::{Array4x12, Array4x4};
use caliptra_cfi_derive::Launder;
use caliptra_registers::soc_ifc::SocIfcReg;
use zerocopy::AsBytes;
Expand Down Expand Up @@ -342,6 +342,19 @@ impl FuseBank<'_> {
let soc_ifc_regs = self.soc_ifc.regs();
soc_ifc_regs.fuse_lms_revocation().read()
}

/// Get the manufactoring debug unlock token
///
/// # Arguments
/// * None
///
/// # Returns
/// manufactoring debug unlock token
///
pub fn manuf_dbg_unlock_token(&self) -> Array4x4 {
let soc_ifc_regs = self.soc_ifc.regs();
Array4x4::read_from_reg(soc_ifc_regs.fuse_manuf_dbg_unlock_token())
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion drivers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub mod pic;
pub mod printer;
mod sha1;
mod sha256;
mod sha2_512_384;
pub mod sha2_512_384;
mod sha2_512_384acc;
mod soc_ifc;
mod trng;
Expand Down
8 changes: 8 additions & 0 deletions drivers/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,14 @@ impl MailboxRecvTxn<'_> {
self.state = MailboxOpState::Idle;
Ok(())
}

///
/// Set UC TAP unlock
///
pub fn set_uc_tap_unlock(&mut self, enable: bool) {
let mbox = self.mbox.regs_mut();
mbox.tap_mode().modify(|w| w.enabled(enable))
}
}

impl Drop for MailboxRecvTxn<'_> {
Expand Down
Loading