diff --git a/Cargo.lock b/Cargo.lock index 4ab38ea8f6..a6d44e2f97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -746,6 +746,7 @@ dependencies = [ "caliptra-emu-cpu", "caliptra-error", "caliptra-hw-model", + "caliptra-hw-model-types", "caliptra-image-crypto", "caliptra-image-elf", "caliptra-image-fake-keys", diff --git a/api/src/soc_mgr.rs b/api/src/soc_mgr.rs index 7c7aedf85c..ec69e9f7a2 100644 --- a/api/src/soc_mgr.rs +++ b/api/src/soc_mgr.rs @@ -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)); diff --git a/api/types/src/lib.rs b/api/types/src/lib.rs index 7d6fb712df..ed8069fff1 100644 --- a/api/types/src/lib.rs +++ b/api/types/src/lib.rs @@ -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 { @@ -82,6 +85,49 @@ impl SecurityState { } } +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct DbgManufServiceRegReq(u32); +impl From for DbgManufServiceRegReq { + fn from(value: u32) -> Self { + Self(value) + } +} +impl From 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] @@ -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 { @@ -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, } } } diff --git a/drivers/src/fuse_bank.rs b/drivers/src/fuse_bank.rs index 85f49a6e81..182febcc79 100644 --- a/drivers/src/fuse_bank.rs +++ b/drivers/src/fuse_bank.rs @@ -351,7 +351,6 @@ impl FuseBank<'_> { /// # 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()) diff --git a/hw-model/src/lib.rs b/hw-model/src/lib.rs index 7467662b42..10c9568aa1 100644 --- a/hw-model/src/lib.rs +++ b/hw-model/src/lib.rs @@ -43,7 +43,7 @@ mod output; mod rv32_builder; pub use api::mailbox::mbox_write_fifo; -pub use api_types::{DeviceLifecycle, Fuses, SecurityState, U4}; +pub use api_types::{DbgManufServiceRegReq, DeviceLifecycle, Fuses, SecurityState, U4}; pub use caliptra_emu_bus::BusMmio; pub use caliptra_emu_cpu::{CodeRange, ImageInfo, StackInfo, StackRange}; use output::ExitStatus; @@ -155,6 +155,10 @@ pub struct InitParams<'a> { pub security_state: SecurityState, + pub dbg_manuf_service: DbgManufServiceRegReq, + + pub debug_intent: bool, + // The silicon obfuscation key passed to caliptra_top. pub cptra_obf_key: [u32; 8], @@ -205,6 +209,8 @@ impl<'a> Default for InitParams<'a> { log_writer: Box::new(stdout()), security_state: *SecurityState::default() .set_device_lifecycle(DeviceLifecycle::Unprovisioned), + dbg_manuf_service: Default::default(), + debug_intent: false, cptra_obf_key: DEFAULT_CPTRA_OBF_KEY, itrng_nibbles, etrng_responses, diff --git a/hw-model/src/model_emulated.rs b/hw-model/src/model_emulated.rs index f94c22e4f4..6541e9dbf3 100644 --- a/hw-model/src/model_emulated.rs +++ b/hw-model/src/model_emulated.rs @@ -160,6 +160,8 @@ impl HwModel for ModelEmulated { cpu_enabled_cloned.set(true); }), security_state: params.security_state, + dbg_manuf_service_req: params.dbg_manuf_service, + debug_intent: params.debug_intent, cptra_obf_key: params.cptra_obf_key, itrng_nibbles: Some(params.itrng_nibbles), diff --git a/hw-model/types/src/lib.rs b/hw-model/types/src/lib.rs index 2e054442e1..ce1e72f874 100644 --- a/hw-model/types/src/lib.rs +++ b/hw-model/types/src/lib.rs @@ -27,6 +27,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]; + struct SecurityStateWrapper(SecurityState); impl std::fmt::Debug for SecurityStateWrapper { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/rom/dev/Cargo.toml b/rom/dev/Cargo.toml index b1e0822892..b6acd50011 100644 --- a/rom/dev/Cargo.toml +++ b/rom/dev/Cargo.toml @@ -39,6 +39,7 @@ caliptra-builder.workspace = true caliptra-emu-cpu.workspace = true caliptra-hw-model.workspace = true +caliptra-hw-model-types.workspace = true caliptra-image-elf.workspace = true caliptra-image-fake-keys.workspace = true caliptra-image-gen.workspace = true diff --git a/rom/dev/tests/rom_integration_tests/main.rs b/rom/dev/tests/rom_integration_tests/main.rs index 73e7b76021..d18fa13121 100644 --- a/rom/dev/tests/rom_integration_tests/main.rs +++ b/rom/dev/tests/rom_integration_tests/main.rs @@ -6,6 +6,7 @@ mod rv32_unit_tests; mod test_capabilities; mod test_cfi; mod test_cpu_fault; +mod test_debug_unlock; mod test_dice_derivations; mod test_fake_rom; mod test_fips_hooks; diff --git a/rom/dev/tests/rom_integration_tests/test_debug_unlock.rs b/rom/dev/tests/rom_integration_tests/test_debug_unlock.rs new file mode 100644 index 0000000000..7f747fb4af --- /dev/null +++ b/rom/dev/tests/rom_integration_tests/test_debug_unlock.rs @@ -0,0 +1,58 @@ +// Licensed under the Apache-2.0 license + +use caliptra_api::mailbox::{CommandId, MailboxReqHeader, ManufDebugUnlockTokenReq}; +use caliptra_api::SocManager; +use caliptra_builder::firmware::ROM_WITH_UART; +use caliptra_hw_model::{DbgManufServiceRegReq, DeviceLifecycle, HwModel, SecurityState}; +use zerocopy::AsBytes; + +#[test] +fn test_dbg_unlock_manuf() { + let security_state = *SecurityState::default() + .set_debug_locked(true) + .set_device_lifecycle(DeviceLifecycle::Manufacturing); + + let dbg_manuf_service = *DbgManufServiceRegReq::default().set_manuf_dbg_unlock_req(true); + + let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap(); + + let mut hw = caliptra_hw_model::new( + caliptra_hw_model::InitParams { + rom: &rom, + security_state, + dbg_manuf_service, + debug_intent: true, + ..Default::default() + }, + caliptra_hw_model::BootParams::default(), + ) + .unwrap(); + + let token = ManufDebugUnlockTokenReq { + token: caliptra_hw_model_types::DEFAULT_MANUF_DEBUG_UNLOCK_TOKEN + .as_bytes() + .try_into() + .unwrap(), + ..Default::default() + }; + let checksum = caliptra_common::checksum::calc_checksum( + u32::from(CommandId::MANUF_DEBUG_UNLOCK_REQ_TOKEN), + &token.as_bytes()[4..], + ); + let token = ManufDebugUnlockTokenReq { + hdr: MailboxReqHeader { chksum: checksum }, + ..token + }; + hw.mailbox_execute( + CommandId::MANUF_DEBUG_UNLOCK_REQ_TOKEN.into(), + token.as_bytes(), + ) + .unwrap(); + + hw.step_until(|m| { + let resp = m.soc_ifc().ss_dbg_manuf_service_reg_rsp().read(); + resp.manuf_dbg_unlock_success() + }); +} + +// [TODO][CAP2] write unit test for production diff --git a/sw-emulator/lib/periph/src/root_bus.rs b/sw-emulator/lib/periph/src/root_bus.rs index 1864c0d714..1dd6e5b5c0 100644 --- a/sw-emulator/lib/periph/src/root_bus.rs +++ b/sw-emulator/lib/periph/src/root_bus.rs @@ -22,7 +22,7 @@ use crate::{ AsymEcc384, Csrng, Doe, EmuCtrl, HashSha256, HashSha512, HmacSha, KeyVault, MailboxExternal, MailboxInternal, MailboxRam, Sha512Accelerator, SocRegistersInternal, Uart, }; -use caliptra_api_types::SecurityState; +use caliptra_api_types::{DbgManufServiceRegReq, SecurityState}; use caliptra_emu_bus::{Clock, Ram, Rom}; use caliptra_emu_cpu::{Pic, PicMmioRegisters}; use caliptra_emu_derive::Bus; @@ -213,6 +213,8 @@ pub struct CaliptraRootBusArgs { pub log_dir: PathBuf, // The security state wires provided to caliptra_top pub security_state: SecurityState, + pub dbg_manuf_service_req: DbgManufServiceRegReq, + pub debug_intent: bool, /// Callback to customize application behavior when /// a write to the tb-services register write is performed. @@ -234,6 +236,8 @@ impl Default for CaliptraRootBusArgs { rom: Default::default(), log_dir: Default::default(), security_state: Default::default(), + dbg_manuf_service_req: Default::default(), + debug_intent: false, tb_services_cb: Default::default(), ready_for_fw_cb: Default::default(), upload_update_fw: Default::default(), diff --git a/sw-emulator/lib/periph/src/soc_reg.rs b/sw-emulator/lib/periph/src/soc_reg.rs index 9a95d44498..c4100270e5 100644 --- a/sw-emulator/lib/periph/src/soc_reg.rs +++ b/sw-emulator/lib/periph/src/soc_reg.rs @@ -214,6 +214,28 @@ register_bitfields! [ DEBUG_INTENT OFFSET(0) NUMBITS(1) [], ], + /// 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) [], + ], + /// Per-Type Interrupt Enable Register GlobalIntrEn [ ERROR_EN OFFSET(0) NUMBITS(1) [], @@ -709,12 +731,12 @@ struct SocRegistersImpl { #[register(offset = 0x520)] ss_uds_seed_base_addr_l: ReadOnlyRegister, - #[register(offset = 0x530)] - ss_debug_intent: ReadOnlyRegister, - #[register(offset = 0x524)] ss_uds_seed_base_addr_h: ReadOnlyRegister, + #[register(offset = 0x530)] + ss_debug_intent: ReadOnlyRegister, + #[register(offset = 0x5c0)] ss_dbg_manuf_service_reg_req: ReadWriteRegister, @@ -913,7 +935,9 @@ impl SocRegistersImpl { fuse_mldsa_revocation: Default::default(), fuse_soc_stepping_id: ReadWriteRegister::new(0), fuse_manuf_dbg_unlock_token: [0; 4], - ss_debug_intent: ReadOnlyRegister::new(0), + ss_debug_intent: ReadOnlyRegister::new(if args.debug_intent { 1 } else { 0 }), + ss_dbg_manuf_service_reg_req: ReadWriteRegister::new(args.dbg_manuf_service_req.into()), + ss_dbg_manuf_service_reg_rsp: ReadWriteRegister::new(0), internal_obf_key: args.cptra_obf_key, internal_iccm_lock: ReadWriteRegister::new(0), internal_fw_update_reset: ReadWriteRegister::new(0),