diff --git a/emulator/app/src/emulator.rs b/emulator/app/src/emulator.rs index b2309364f..778f13347 100644 --- a/emulator/app/src/emulator.rs +++ b/emulator/app/src/emulator.rs @@ -259,6 +259,8 @@ pub struct EmulatorArgs { pub fuse_soc_manifest_max_svn: Option, #[arg(long)] pub fuse_vendor_hashes_prod_partition: Option, + #[arg(long)] + pub fuse_vendor_test_partition: Option, } pub struct Emulator { @@ -731,6 +733,9 @@ impl Emulator { let fuse_vendor_hashes_prod_partition = cli .fuse_vendor_hashes_prod_partition .map(|fuse| hex::decode(fuse).expect("Invalid hex in vendor_hashes_prod_partition")); + let fuse_vendor_test_partition = cli + .fuse_vendor_test_partition + .map(|fuse| hex::decode(fuse).expect("Invalid hex in vendor_test_partition")); let lc = LcCtrl::new(); @@ -744,6 +749,7 @@ impl Emulator { soc_manifest_svn: cli.fuse_soc_manifest_svn.map(|v| v as u8), soc_manifest_max_svn: cli.fuse_soc_manifest_max_svn.map(|v| v as u8), vendor_hashes_prod_partition: fuse_vendor_hashes_prod_partition, + vendor_test_partition: fuse_vendor_test_partition, ..Default::default() }, )?; diff --git a/emulator/cbinding/src/lib.rs b/emulator/cbinding/src/lib.rs index a6f05a868..f80e78637 100644 --- a/emulator/cbinding/src/lib.rs +++ b/emulator/cbinding/src/lib.rs @@ -195,6 +195,7 @@ pub struct CEmulatorConfig { pub fuse_soc_manifest_svn: c_longlong, pub fuse_soc_manifest_max_svn: c_longlong, pub fuse_vendor_hashes_prod_partition: *const c_char, // Optional, can be null + pub fuse_vendor_test_partition: *const c_char, // Optional, can be null // External device callbacks (can be null) pub external_read_callback: *const std::ffi::c_void, @@ -344,6 +345,7 @@ pub unsafe extern "C" fn emulator_init( fuse_vendor_hashes_prod_partition: convert_optional_c_string( config.fuse_vendor_hashes_prod_partition, ), + fuse_vendor_test_partition: convert_optional_c_string(config.fuse_vendor_test_partition), }; // Convert C callbacks to Rust callbacks if provided diff --git a/emulator/cbinding/src/simple_test.rs b/emulator/cbinding/src/simple_test.rs index e8018674d..9f3ca917b 100644 --- a/emulator/cbinding/src/simple_test.rs +++ b/emulator/cbinding/src/simple_test.rs @@ -88,6 +88,7 @@ fn test_emulator_args_creation() { fuse_soc_manifest_max_svn: None, fuse_soc_manifest_svn: None, fuse_vendor_hashes_prod_partition: None, + fuse_vendor_test_partition: None, }; println!("EmulatorArgs created successfully"); diff --git a/emulator/periph/src/otp.rs b/emulator/periph/src/otp.rs index e2864fc15..2d7f47ffd 100644 --- a/emulator/periph/src/otp.rs +++ b/emulator/periph/src/otp.rs @@ -115,6 +115,7 @@ pub struct OtpArgs { pub soc_manifest_svn: Option, pub soc_manifest_max_svn: Option, pub vendor_hashes_prod_partition: Option>, + pub vendor_test_partition: Option>, } //#[derive(Bus)] @@ -213,6 +214,13 @@ impl Otp { otp.partitions[dst_start..dst_start + copy_len] .copy_from_slice(&vendor_hashes_prod_partition[..copy_len]); } + if let Some(vendor_test_partition) = args.vendor_test_partition { + let dst_start = fuses::VENDOR_TEST_PARTITION_BYTE_OFFSET; + let max_len = fuses::VENDOR_TEST_PARTITION_BYTE_SIZE; + let copy_len = vendor_test_partition.len().min(max_len); + otp.partitions[dst_start..dst_start + copy_len] + .copy_from_slice(&vendor_test_partition[..copy_len]); + } // if there were digests that were pending a reset, then calculate them now otp.calculate_digests()?; diff --git a/platforms/emulator/rom/src/mcu_image_verifier.rs b/platforms/emulator/rom/src/mcu_image_verifier.rs index 09db0df10..fd3fa87da 100644 --- a/platforms/emulator/rom/src/mcu_image_verifier.rs +++ b/platforms/emulator/rom/src/mcu_image_verifier.rs @@ -12,6 +12,7 @@ pub struct McuImageVerifier; impl ImageVerifier for McuImageVerifier { fn verify_header(&self, _header: &[u8], _fuses: &Fuses) -> bool { + // TODO: make this unconditional and use proper fuses for it instead of test fuses #[cfg(any(feature = "test-mcu-svn-gt-fuse", feature = "test-mcu-svn-lt-fuse"))] { let Ok((header, _)) = McuImageHeader::ref_from_prefix(_header) else { @@ -21,7 +22,7 @@ impl ImageVerifier for McuImageVerifier { let mut fuse_vendor_svn: u16 = 0; // Use the first 128 bits of vendor test partition as SVN - for byte in _fuses.vendor_hashes_prod_partition[..16].iter() { + for byte in _fuses.vendor_test_partition[..16].iter() { // Count contiguous 1's in the byte let mut count = 0; for bit in 0..8 { diff --git a/rom/src/fuses.rs b/rom/src/fuses.rs index 4ea557ba0..d6dcecacb 100644 --- a/rom/src/fuses.rs +++ b/rom/src/fuses.rs @@ -675,12 +675,12 @@ impl Otp { fuses::VENDOR_HASHES_PROD_PARTITION_BYTE_SIZE, &mut fuses.vendor_hashes_prod_partition, )?; - // romtime::println!("[mcu-rom-otp] Reading vendor revocations production partition"); - // self.read_data( - // fuses::VENDOR_REVOCATIONS_PROD_PARTITION_BYTE_OFFSET, - // fuses::VENDOR_REVOCATIONS_PROD_PARTITION_BYTE_SIZE, - // &mut fuses.vendor_revocations_prod_partition, - // )?; + romtime::println!("[mcu-rom-otp] Reading vendor revocations production partition"); + self.read_data( + fuses::VENDOR_REVOCATIONS_PROD_PARTITION_BYTE_OFFSET, + fuses::VENDOR_REVOCATIONS_PROD_PARTITION_BYTE_SIZE, + &mut fuses.vendor_revocations_prod_partition, + )?; // romtime::println!("[mcu-rom-otp] Reading vendor non-secret production partition"); // self.read_data( // fuses::VENDOR_NON_SECRET_PROD_PARTITION_BYTE_OFFSET, diff --git a/rom/src/rom.rs b/rom/src/rom.rs index 9d2328bec..704e08691 100644 --- a/rom/src/rom.rs +++ b/rom/src/rom.rs @@ -272,9 +272,65 @@ impl Soc { } // TODO: vendor-specific fuses when those are supported - // TODO: load ECC Revocation CSRs. - // TODO: load LMS Revocation CSRs. - // TODO: load MLDSA Revocation CSRs. + // Load Owner ECC/LMS/MLDSA revocation CSRs. + // ECC Revocation. + let vendor_ecc_revocation = + u32::from_le_bytes(fuses.cptra_core_ecc_revocation_0().try_into().unwrap()); + self.registers + .fuse_ecc_revocation + .set(vendor_ecc_revocation); + + // LMS Revocation. + + let vendor_lms_revocation = u32::from_le_bytes( + fuses + .cptra_core_lms_revocation_0() + .try_into() + .unwrap_or_else(|_| { + fatal_error(McuError::ROM_SOC_KEY_MANIFEST_PK_HASH_LEN_MISMATCH) + }), + ); + self.registers + .fuse_lms_revocation + .set(vendor_lms_revocation); + + // MLDSA Revocation. + let vendor_mldsa_revocation = u32::from_le_bytes( + fuses + .cptra_core_mldsa_revocation_0() + .try_into() + .unwrap_or_else(|_| { + fatal_error(McuError::ROM_SOC_KEY_MANIFEST_PK_HASH_LEN_MISMATCH) + }), + ); + self.registers + .fuse_mldsa_revocation + .set(vendor_mldsa_revocation); + + // Owner PK Hash. + // TBD: Device Ownership Transfer + if !fuses.cptra_ss_owner_pk_hash().iter().all(|&x| x == 0) { + romtime::print!("[mcu-fuse-write] Writing fuse key owner PK hash: "); + + if size_of_val(fuses.cptra_ss_owner_pk_hash()) + != size_of_val(&self.registers.cptra_owner_pk_hash) + { + fatal_error(McuError::ROM_SOC_KEY_MANIFEST_PK_HASH_LEN_MISMATCH); + } + for i in 0..self.registers.cptra_owner_pk_hash.len() { + let word = u32::from_le_bytes( + fuses.cptra_ss_owner_pk_hash()[i * 4..i * 4 + 4] + .try_into() + .unwrap_or_else(|_| { + fatal_error(McuError::ROM_SOC_KEY_MANIFEST_PK_HASH_LEN_MISMATCH) + }), + ); + romtime::print!("{}", HexWord(word)); + self.registers.cptra_owner_pk_hash[i].set(word); + } + romtime::println!(""); + } + // TODO: load HEK Seed CSRs. // SoC Stepping ID (only 16-bits are relevant). diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index e4f4d0547..5faaec7df 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -281,7 +281,7 @@ mod test { hw_revision: Option, fuse_soc_manifest_svn: Option, fuse_soc_manifest_max_svn: Option, - fuse_vendor_hashes_prod_partition: Option>, + fuse_vendor_test_partition: Option>, ) -> i32 { let mut cargo_run_args = vec![ "run", @@ -451,12 +451,11 @@ mod test { cargo_run_args.push(soc_manifest_max_svn_str.as_str()); } - let fuse_vendor_hashes_prod_partition_str; - if let Some(fuse_vendor_hashes_prod_partition) = fuse_vendor_hashes_prod_partition { - cargo_run_args.push("--fuse-vendor-hashes-prod-partition"); - fuse_vendor_hashes_prod_partition_str = - hex::encode(fuse_vendor_hashes_prod_partition); - cargo_run_args.push(fuse_vendor_hashes_prod_partition_str.as_str()); + let fuse_vendor_test_partition_str; + if let Some(fuse_vendor_test_partition) = fuse_vendor_test_partition { + cargo_run_args.push("--fuse-vendor-test-partition"); + fuse_vendor_test_partition_str = hex::encode(fuse_vendor_test_partition); + cargo_run_args.push(fuse_vendor_test_partition_str.as_str()); } println!("Running test firmware {}", feature.replace("_", "-"));