Skip to content

Commit

Permalink
[feat] UDS Programming Flow
Browse files Browse the repository at this point in the history
This change adds the UDS programming flow to the ROM.
  • Loading branch information
mhatrevi committed Dec 16, 2024
1 parent 0001d50 commit bebe372
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 11 deletions.
25 changes: 25 additions & 0 deletions drivers/src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,31 @@ impl Dma {
Ok(())
}

/// Write an arbitrary length buffer to the target address.
///
/// # Arguments
///
/// * `write_addr` - Target address to write to
/// * `buffer` - Buffer to write
///
/// # Returns
///
/// * CaliptraResult<()> - Success or failure
pub fn write_buffer(&mut self, write_addr: usize, buffer: &[u8]) -> CaliptraResult<()> {
self.flush();

let write_transaction = DmaWriteTransaction {
write_addr,
fixed_addr: false,
length: buffer.len() as u32,
origin: DmaWriteOrigin::AhbFifo,
};
self.dma_write_fifo(buffer)?;
self.setup_dma_write(write_transaction);
self.do_transaction()?;
Ok(())
}

/// Transfer payload to mailbox
///
/// The mailbox lock needs to be acquired before this can be called
Expand Down
42 changes: 42 additions & 0 deletions drivers/src/soc_ifc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,48 @@ impl SocIfc {
.notif_internal_intr_r()
.write(|w| w.notif_cmd_avail_sts(true));
}

pub fn uds_program_req(&self) -> bool {
self.soc_ifc
.regs()
.ss_dbg_manuf_service_reg_req()
.read()
.uds_program_req()
}

pub fn set_uds_programming_flow_state(&mut self, in_progress: bool) {
self.soc_ifc
.regs_mut()
.ss_dbg_manuf_service_reg_rsp()
.write(|w| w.uds_program_in_progress(in_progress));
}

pub fn set_uds_programming_flow_status(&mut self, flow_succeeded: bool) {
self.soc_ifc
.regs_mut()
.ss_dbg_manuf_service_reg_rsp()
.write(|w| {
if flow_succeeded {
w.uds_program_success(true);
w.uds_program_fail(false)
} else {
w.uds_program_success(false);
w.uds_program_fail(true)
}
});
}

pub fn uds_seed_dest_base_addr_low(&self) -> u32 {
self.soc_ifc.regs().ss_uds_seed_base_addr_l().read()
}

pub fn active_mode(&self) -> bool {
self.soc_ifc
.regs()
.cptra_hw_config()
.read()
.active_mode_en()
}
}

bitflags::bitflags! {
Expand Down
5 changes: 5 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,11 @@ impl CaliptraError {
pub const ROM_CFI_PANIC_FAKE_TRNG_USED_WITH_DEBUG_LOCK: CaliptraError =
CaliptraError::new_const(0x104005D);

/// ROM UDS Programming Errors
pub const ROM_UDS_PROG_ILLEGAL_LIFECYCLE_STATE: CaliptraError =
CaliptraError::new_const(0x01045000);
pub const ROM_UDS_PROG_IN_PASSIVE_MODE: CaliptraError = CaliptraError::new_const(0x01045001);

/// ROM Global Errors
pub const ROM_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x01050001);
pub const ROM_GLOBAL_EXCEPTION: CaliptraError = CaliptraError::new_const(0x01050002);
Expand Down
10 changes: 6 additions & 4 deletions rom/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,15 @@ The following flows are conducted exclusively when the ROM is operating in ACTIV
The following flows are conducted when the ROM is operating in the manufacturing mode, indicated by a value of `DEVICE_MANUFACTURING` (0x1) in the `CPTRA_SECURITY_STATE` register `device_lifecycle` bits.

#### UDS Provisioning
1. On reset, the ROM checks if the `UDS_PROGRAM_REQ` bit in the `CPTRA_DBG_MANUF_SERVICE_REQ_REG` register is set. If the bit is set, the ROM initiates the UDS seed programming flow.
1. On reset, the ROM checks if the `UDS_PROGRAM_REQ` bit in the `SS_DBG_MANUF_SERVICE_REG_REQ` register is set. If the bit is set, ROM initiates the UDS seed programming flow by setting the `UDS_PROGRAM_IN_PROGRESS` bit in the `SS_DBG_MANUF_SERVICE_REG_RSP` register.

2. In this procedure, the ROM retrieves a 512-bit value from the iTRNG and writes it to the address specified by the `UDS_SEED_OFFSET` register, utilizing DMA hardware assistance.
2. ROM then retrieves a 512-bit value from the iTRNG and writes it to the address specified by the `SS_UDS_SEED_BASE_ADDR_L` register, utilizing DMA hardware assistance.

3. Following the DMA operation, the ROM updates the `UDS_PROGRAM_REQ` bit in the `CPTRA_DBG_MANUF_SERVICE_RSP_REG` register to either `UDS_PROGRAM_SUCCESS` or `UDS_PROGRAM_FAIL`, indicating the outcome of the operation.
3. Following the DMA operation, ROM updates the `UDS_PROGRAM_SUCCESS` or the `UDS_PROGRAM_FAIL` bit in the `SS_DBG_MANUF_SERVICE_REG_RSP` register to indicate the outcome of the operation.

4. The manufacturing process then polls this bit and continues with the fuse burning flow as outlined by the fuse controller specifications and SOC-specific VR methodologies.
4. ROM then resets the `UDS_PROGRAM_IN_PROGRESS` bit in the `SS_DBG_MANUF_SERVICE_REG_RSP` register to indicate completion of the programming.

5. The manufacturing process polls this bit and continues with the fuse burning flow as outlined by the fuse controller specifications and SOC-specific VR methodologies.

#### Debug Unlock
1. On reset, the ROM checks if the `MANUF_DEBUG_UNLOCK_REQ` bit in the `CPTRA_DBG_MANUF_SERVICE_REQ_REG` register and the `DEBUG_INTENT_STRAP` register are set
Expand Down
2 changes: 2 additions & 0 deletions rom/dev/src/flow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ Abstract:
mod cold_reset;
#[cfg(feature = "fake-rom")]
mod fake;
pub(crate) mod uds_programming;
mod update_reset;
mod warm_reset;

use crate::cprintln;
pub use crate::flow::uds_programming::UdsProgrammingFlow;
use crate::{handle_fatal_error, rom_env::RomEnv};
#[cfg(not(feature = "no-cfi"))]
use caliptra_cfi_derive::cfi_mod_fn;
Expand Down
87 changes: 87 additions & 0 deletions rom/dev/src/flow/uds_programming.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*++
Licensed under the Apache-2.0 license.
File Name:
uds_programming.rs
Abstract:
File contains the implementation of UDS programming flow.
--*/

use crate::rom_env::RomEnv;
#[cfg(not(feature = "no-cfi"))]
use caliptra_cfi_derive::cfi_impl_fn;
use caliptra_common::cprintln;
use caliptra_drivers::Lifecycle;
use caliptra_drivers::{CaliptraError, CaliptraResult};
use zerocopy::AsBytes;

/// UDS Programming Flow
pub struct UdsProgrammingFlow {}

impl UdsProgrammingFlow {
#[inline(never)]
#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
pub fn program_uds(env: &mut RomEnv) -> CaliptraResult<()> {
cprintln!("[uds] ++");

// Check if UDS programming is requested.
if !env.soc_ifc.uds_program_req() {
return Ok(());
}

cprintln!("[uds] ++");

// Check if ROM is running in Active mode.
if !env.soc_ifc.active_mode() {
cprintln!("[uds] ROM is not in Active mode.");
return Err(CaliptraError::ROM_UDS_PROG_IN_PASSIVE_MODE);
}

// Check if ROM is in manufacturing mode.
if env.soc_ifc.lifecycle() != Lifecycle::Manufacturing {
cprintln!("[uds] ROM is not in manufacturing mode.");
return Err(CaliptraError::ROM_UDS_PROG_ILLEGAL_LIFECYCLE_STATE);
}

// Update the UDS programming state.
env.soc_ifc
.set_uds_programming_flow_state(true /* in_progress */);

let result = (|| {
// Generate a 512-bit random value..
let mut seed = [0u32; 16];
let seed1 = env.trng.generate()?;
let seed2 = env.trng.generate()?;
seed[..12].copy_from_slice(&seed1.0);
seed[12..16].copy_from_slice(&seed2.0[0..4]);

// Write the seed to the UDS_SEED_OFFSET using DMA assist.
cprintln!("[uds] Writing seed to UDS_SEED_OFFSET");
env.dma.write_buffer(
env.soc_ifc.uds_seed_dest_base_addr_low() as usize,
seed.as_bytes(),
)?;
Ok(())
})();

// Set the UDS programming result.
env.soc_ifc.set_uds_programming_flow_status(result.is_ok());

// Update the UDS programming state.
env.soc_ifc
.set_uds_programming_flow_state(false /* in_progress */);

cprintln!(
"[uds] UDS programming flow completed with status: {}",
if result.is_ok() { "SUCCESS" } else { "FAILURE" }
);

cprintln!("[uds] --");

result
}
}
5 changes: 5 additions & 0 deletions rom/dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ pub extern "C" fn rom_entry() -> ! {
};
cprintln!("[state] LifecycleState = {}", _lifecyle);

// UDS programming.
if let Err(err) = crate::flow::UdsProgrammingFlow::program_uds(&mut env) {
handle_fatal_error(err.into());
}

if cfg!(feature = "fake-rom")
&& (env.soc_ifc.lifecycle() == caliptra_drivers::Lifecycle::Production)
&& !(env.soc_ifc.prod_en_in_fake_mode())
Expand Down
13 changes: 9 additions & 4 deletions rom/dev/src/rom_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ Abstract:

use crate::fht::FhtDataStore;
use caliptra_drivers::{
DataVault, DeobfuscationEngine, Ecc384, Hmac, KeyVault, Lms, Mailbox, Mldsa87, PcrBank,
DataVault, DeobfuscationEngine, Dma, Ecc384, Hmac, KeyVault, Lms, Mailbox, Mldsa87, PcrBank,
PersistentDataAccessor, Sha1, Sha256, Sha2_512_384, Sha2_512_384Acc, SocIfc, Trng,
};
use caliptra_error::CaliptraResult;
use caliptra_registers::{
csrng::CsrngReg, doe::DoeReg, dv::DvReg, ecc::EccReg, entropy_src::EntropySrcReg,
hmac::HmacReg, kv::KvReg, mbox::MboxCsr, mldsa::MldsaReg, pv::PvReg, sha256::Sha256Reg,
sha512::Sha512Reg, sha512_acc::Sha512AccCsr, soc_ifc::SocIfcReg, soc_ifc_trng::SocIfcTrngReg,
axi_dma::AxiDmaReg, csrng::CsrngReg, doe::DoeReg, dv::DvReg, ecc::EccReg,
entropy_src::EntropySrcReg, hmac::HmacReg, kv::KvReg, mbox::MboxCsr, mldsa::MldsaReg,
pv::PvReg, sha256::Sha256Reg, sha512::Sha512Reg, sha512_acc::Sha512AccCsr, soc_ifc::SocIfcReg,
soc_ifc_trng::SocIfcTrngReg,
};

/// Rom Context
Expand Down Expand Up @@ -79,6 +80,9 @@ pub struct RomEnv {

/// Mldsa87 Engine
pub mldsa87: Mldsa87,

/// Dma engine
pub dma: Dma,
}

impl RomEnv {
Expand Down Expand Up @@ -108,6 +112,7 @@ impl RomEnv {
trng,
persistent_data: PersistentDataAccessor::new(),
mldsa87: Mldsa87::new(MldsaReg::new()),
dma: Dma::new(AxiDmaReg::new()),
})
}
}
55 changes: 52 additions & 3 deletions sw-emulator/lib/periph/src/soc_reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,37 @@ register_bitfields! [
NOTIF_GEN_IN_TOGGLE_TRIG OFFSET(5) NUMBITS(1) [],
RSVD OFFSET(6) NUMBITS(26) [],
],

/// SubSytem Debug Manufacturing Service Request Register
SsDbgManufServiceRegReq [
MANUF_DBG_UNLOCK_REQ OFFSET(0) NUMBITS(1) [],
PROD_DBG_UNLOCK_REQ OFFSET(1) NUMBITS(1) [],
UDS_PROGRAM_REQ OFFSET(2) NUMBITS(1) [],
RSVD OFFSET(3) NUMBITS(29) [],
],

/// SubSytem Debug Manufacturing Service Response Register
SsDbgManufServiceRegRsp [
MANUF_DBG_UNLOCK_SUCCESS OFFSET(0) NUMBITS(1) [],
MANUF_DBG_UNLOCK_FAIL OFFSET(1) NUMBITS(1) [],
MANUF_DBG_UNLOCK_IN_PROGRESS OFFSET(2) NUMBITS(1) [],
PROD_DBG_UNLOCK_SUCCESS OFFSET(3) NUMBITS(1) [],
PROD_DBG_UNLOCK_FAIL OFFSET(4) NUMBITS(1) [],
PROD_DBG_UNLOCK_IN_PROGRESS OFFSET(5) NUMBITS(1) [],
UDS_PROGRAM_SUCCESS OFFSET(6) NUMBITS(1) [],
UDS_PROGRAM_FAIL OFFSET(7) NUMBITS(1) [],
UDS_PROGRAM_IN_PROGRESS OFFSET(8) NUMBITS(1) [],
RSVD OFFSET(9) NUMBITS(23) [],
],

/// Hardware Configuration
HwConfig [
ITRNG_EN OFFSET(0) NUMBITS(1) [],
RSVD_EN OFFSET(1) NUMBITS(3) [],
LMS_ACC_EN OFFSET(4) NUMBITS(1) [],
ACTIVE_MODE_en OFFSET(5) NUMBITS(1) [],
RSVD OFFSET(6) NUMBITS(26) [],
],
];

/// SOC Register peripheral
Expand Down Expand Up @@ -371,7 +402,9 @@ impl SocRegistersInternal {
}

pub fn set_hw_config(&mut self, val: CptraHwConfigReadVal) {
self.regs.borrow_mut().cptra_hw_config = val.into();
self.regs.borrow_mut().cptra_hw_config = ReadWriteRegister {
reg: InMemoryRegister::<u32, HwConfig::Register>::new(val.into()),
};
}

pub fn external_regs(&self) -> SocRegistersExternal {
Expand Down Expand Up @@ -572,7 +605,7 @@ struct SocRegistersImpl {
cptra_fw_rev_id: [u32; 2],

#[register(offset = 0x00e0, write_fn = write_disabled)]
cptra_hw_config: u32,
cptra_hw_config: ReadWriteRegister<u32, HwConfig::Register>,

#[register(offset = 0x00e4, write_fn = on_write_wdt_timer1_en)]
cptra_wdt_timer1_en: ReadWriteRegister<u32, WdtEnable::Register>,
Expand Down Expand Up @@ -669,6 +702,18 @@ struct SocRegistersImpl {
#[register_array(offset = 0x34c)]
fuse_manuf_dbg_unlock_token: [u32; FUSE_MANUF_DBG_UNLOCK_TOKEN_SIZE / 4],

#[register(offset = 0x520)]
ss_uds_seed_base_addr_l: ReadOnlyRegister<u32>,

#[register(offset = 0x524)]
ss_uds_seed_base_addr_h: ReadOnlyRegister<u32>,

#[register(offset = 0x5c0)]
ss_dbg_manuf_service_reg_req: ReadWriteRegister<u32, SsDbgManufServiceRegReq::Register>,

#[register(offset = 0x5c4)]
ss_dbg_manuf_service_reg_rsp: ReadWriteRegister<u32, SsDbgManufServiceRegRsp::Register>,

/// INTERNAL_OBF_KEY Register
internal_obf_key: [u32; 8],

Expand Down Expand Up @@ -829,7 +874,7 @@ impl SocRegistersImpl {
cptra_generic_output_wires: Default::default(),
cptra_hw_rev_id: ReadOnlyRegister::new(0x11), // TODO 2.0
cptra_fw_rev_id: Default::default(),
cptra_hw_config: 0,
cptra_hw_config: ReadWriteRegister::new(0), // [TODO][CAP2] Program this
cptra_wdt_timer1_en: ReadWriteRegister::new(0),
cptra_wdt_timer1_ctrl: ReadWriteRegister::new(0),
cptra_wdt_timer1_timeout_period: [0xffff_ffff; 2],
Expand Down Expand Up @@ -896,6 +941,10 @@ impl SocRegistersImpl {
etrng_responses: args.etrng_responses,
pending_etrng_response: None,
op_pending_etrng_response_action: None,
ss_dbg_manuf_service_reg_req: ReadWriteRegister::new(0),
ss_dbg_manuf_service_reg_rsp: ReadWriteRegister::new(0),
ss_uds_seed_base_addr_l: ReadOnlyRegister::new(0), // [TODO][CAP2] Program this
ss_uds_seed_base_addr_h: ReadOnlyRegister::new(0), // [TODO][CAP2] Program this
};
regs
}
Expand Down

0 comments on commit bebe372

Please sign in to comment.