From ac9e8dd8e9742584a012294b6634592b2421b2cd Mon Sep 17 00:00:00 2001 From: Vishal Mhatre Date: Thu, 30 Nov 2023 00:00:41 -0800 Subject: [PATCH] [test] Validate 128K firmware load in ICCM --- builder/src/firmware.rs | 7 +++ image/gen/src/generator.rs | 13 ++-- rom/dev/doc/test-coverage/test-coverage.md | 4 +- .../test_image_validation.rs | 53 +++++++++++++++- rom/dev/tools/test-fmc/src/main.rs | 61 +++++++++++++++++++ rom/dev/tools/test-rt/src/main.rs | 15 +++++ 6 files changed, 144 insertions(+), 9 deletions(-) diff --git a/builder/src/firmware.rs b/builder/src/firmware.rs index 65360de6ea..890e88bd1f 100644 --- a/builder/src/firmware.rs +++ b/builder/src/firmware.rs @@ -297,6 +297,12 @@ pub mod rom_tests { features: &["emu"], }; + pub const TEST_RT_WITH_UART: FwId = FwId { + crate_name: "caliptra-rom-test-rt", + bin_name: "caliptra-rom-test-rt", + features: &["emu"], + }; + pub const FAKE_TEST_FMC_WITH_UART: FwId = FwId { crate_name: "caliptra-rom-test-fmc", bin_name: "caliptra-rom-test-fmc", @@ -398,6 +404,7 @@ pub const REGISTERED_FW: &[&FwId] = &[ &rom_tests::FAKE_TEST_FMC_WITH_UART, &rom_tests::TEST_FMC_INTERACTIVE, &rom_tests::FAKE_TEST_FMC_INTERACTIVE, + &rom_tests::TEST_RT_WITH_UART, &fmc_tests::MOCK_RT_WITH_UART, &fmc_tests::MOCK_RT_INTERACTIVE, &runtime_tests::BOOT, diff --git a/image/gen/src/generator.rs b/image/gen/src/generator.rs index a0ac1a634c..6b474e0fae 100644 --- a/image/gen/src/generator.rs +++ b/image/gen/src/generator.rs @@ -45,10 +45,13 @@ impl ImageGenerator { where E: ImageGenratorExecutable, { - if IMAGE_MANIFEST_BYTE_SIZE as u32 + config.fmc.size() + config.runtime.size() - > IMAGE_BYTE_SIZE as u32 - { - bail!("Image larger than {IMAGE_BYTE_SIZE} bytes"); + let image_size = + IMAGE_MANIFEST_BYTE_SIZE as u32 + config.fmc.size() + config.runtime.size(); + if image_size > IMAGE_BYTE_SIZE as u32 { + bail!( + "Image larger than {IMAGE_BYTE_SIZE} bytes; image size:{} bytes", + image_size + ); } // Create FMC TOC & Content @@ -64,7 +67,7 @@ impl ImageGenerator { // Check if fmc and runtime image load address ranges don't overlap. if fmc_toc.overlaps(&runtime_toc) { bail!( - "FMC:[{0}:{1}] and Runtime:[{2}:{3}] load address ranges overlap", + "FMC:[{:#x?}:{:#x?}] and Runtime:[{:#x?}:{:#x?}] load address ranges overlap", fmc_toc.load_addr, fmc_toc.load_addr + fmc_toc.size - 1, runtime_toc.load_addr, diff --git a/rom/dev/doc/test-coverage/test-coverage.md b/rom/dev/doc/test-coverage/test-coverage.md index 37e491d9d1..ed351bfb56 100644 --- a/rom/dev/doc/test-coverage/test-coverage.md +++ b/rom/dev/doc/test-coverage/test-coverage.md @@ -130,14 +130,12 @@ Test Scenario| Test Name | ROM Error Code Check for any RUST panics added to the code | **test_panic_missing** | N/A Checks that extended error info is populated correctly upon watchdog timer timeout | **test_rom_wdt_timeout** | ROM_GLOBAL_WDT_EXPIRED Triggers a CPU fault and checks that extended error info is populated correctly | **test_cpu_fault** | ROM_GLOBAL_EXCEPTION +Ensure that boot ROM can load a 128k bundle into ICCM (assert ICCM contents in test) |**test_max_fw_image** | N/A # **Test Gaps** Test Scenario| Test Name | ROM Error Code ---|---|--- Expand `smoke_test` to perform a hitless update and confirm everything is mixed into the identity correctly. | N/A | N/A -Validate fix for #817: warm reset during hitless update | N/A | N/A -Validate fix for #628: warm reset during cold reset | N/A | N/A Stress test: Perform many hitless updates in a row | N/A | N/A -Ensure that boot ROM can load a 128k bundle into ICCM (assert ICCM contents in test) | N/A | N/A Ensure that hitless update flow can update an entire 128k bundle with completely different ICCM contents than original boot | N/A | N/A Run all the tests against the prod ROM (no logging) | N/A | N/A diff --git a/rom/dev/tests/rom_integration_tests/test_image_validation.rs b/rom/dev/tests/rom_integration_tests/test_image_validation.rs index 6f1b6ba017..f011e93a99 100644 --- a/rom/dev/tests/rom_integration_tests/test_image_validation.rs +++ b/rom/dev/tests/rom_integration_tests/test_image_validation.rs @@ -1,7 +1,11 @@ // Licensed under the Apache-2.0 license use caliptra_builder::{ - firmware::{self, rom_tests::TEST_FMC_WITH_UART, APP_WITH_UART, FMC_WITH_UART}, + firmware::{ + self, + rom_tests::{TEST_FMC_INTERACTIVE, TEST_FMC_WITH_UART, TEST_RT_WITH_UART}, + APP_WITH_UART, FMC_WITH_UART, + }, ImageOptions, }; use caliptra_common::memory_layout::{ICCM_ORG, ICCM_SIZE}; @@ -2330,3 +2334,50 @@ fn fmcalias_cert(ldevid_cert: &X509, output: &str) -> X509 { fmcalias_cert } + +#[test] +fn test_max_fw_image() { + let rom = caliptra_builder::build_firmware_rom(firmware::rom_from_env()).unwrap(); + let mut hw = caliptra_hw_model::new(BootParams { + init_params: InitParams { + rom: &rom, + ..Default::default() + }, + ..Default::default() + }) + .unwrap(); + + let image_bundle = caliptra_builder::build_and_sign_image( + &TEST_FMC_INTERACTIVE, + &TEST_RT_WITH_UART, + ImageOptions::default(), + ) + .unwrap(); + + hw.upload_firmware(&image_bundle.to_bytes().unwrap()) + .unwrap(); + + hw.step_until_boot_status(u32::from(ColdResetComplete), true); + + let mut buf = vec![]; + buf.append( + &mut image_bundle + .manifest + .fmc + .image_size() + .to_le_bytes() + .to_vec(), + ); + buf.append( + &mut image_bundle + .manifest + .runtime + .image_size() + .to_le_bytes() + .to_vec(), + ); + buf.append(&mut image_bundle.fmc.to_vec()); + buf.append(&mut image_bundle.runtime.to_vec()); + + hw.mailbox_execute(0x1000_000E, &buf).unwrap(); +} diff --git a/rom/dev/tools/test-fmc/src/main.rs b/rom/dev/tools/test-fmc/src/main.rs index b193ea8ffa..76e2ca2a1d 100644 --- a/rom/dev/tools/test-fmc/src/main.rs +++ b/rom/dev/tools/test-fmc/src/main.rs @@ -40,6 +40,18 @@ const FW_LOAD_CMD_OPCODE: u32 = mailbox_api::CommandId::FIRMWARE_LOAD.0; #[cfg(feature = "std")] pub fn main() {} +// Dummy RO data to max out FMC image size to 16K. +// Note: Adjust this value to account for new changes in this FMC image. +static PAD: [u32; 1163] = { + let mut result = [0xdeadbeef_u32; 1163]; + let mut i = 0; + while i < result.len() { + result[i] = result[i].wrapping_add(i as u32); + i += 1; + } + result +}; + const BANNER: &str = r#" Running Caliptra FMC ... "#; @@ -228,6 +240,9 @@ fn process_mailbox_command(mbox: &caliptra_registers::mbox::RegisterBlock { read_datavault_warmresetentry4(mbox); } + 0x1000_000E => { + validate_fmc_rt_load_in_iccm(mbox); + } _ => {} } } @@ -247,6 +262,52 @@ fn process_mailbox_commands() { process_mailbox_command(&mbox); } +fn validate_fmc_rt_load_in_iccm(mbox: &caliptra_registers::mbox::RegisterBlock) { + let data_vault = unsafe { DataVault::new(DvReg::new()) }; + let fmc_load_addr = data_vault.fmc_entry_point(); + let rt_load_addr = data_vault.rt_entry_point(); + let fmc_size = mbox.dataout().read() as usize; + let rt_size = mbox.dataout().read() as usize; + + let fmc_iccm = unsafe { + let ptr = fmc_load_addr as *mut u32; + core::slice::from_raw_parts_mut(ptr, fmc_size / 4) + }; + + let rt_iccm = unsafe { + let ptr = rt_load_addr as *mut u32; + core::slice::from_raw_parts_mut(ptr, rt_size / 4) + }; + + for (idx, _) in fmc_iccm.iter().enumerate().take(fmc_size / 4) { + let temp = mbox.dataout().read(); + if temp != fmc_iccm[idx] { + cprint!( + "FMC load mismatch at index {} (0x{:08X} != 0x{:08X})", + idx, + temp, + fmc_iccm[idx] + ); + assert!(temp == fmc_iccm[idx]); + cprint!("PAD[{}] = 0x{:08X}", idx, PAD[idx]); + } + } + for (idx, _) in rt_iccm.iter().enumerate().take(rt_size / 4) { + let temp = mbox.dataout().read(); + if temp != rt_iccm[idx] { + cprint!( + "RT load mismatch at index {} (0x{:08X} != 0x{:08X})", + idx, + temp, + rt_iccm[idx] + ); + assert!(temp == rt_iccm[idx]); + } + } + + mbox.status().write(|w| w.status(|w| w.cmd_complete())); +} + fn read_pcr31(mbox: &caliptra_registers::mbox::RegisterBlock) { let pcr_bank = unsafe { PcrBank::new(PvReg::new()) }; let pcr31: [u8; 48] = pcr_bank.read_pcr(PCR_ID_STASH_MEASUREMENT).into(); diff --git a/rom/dev/tools/test-rt/src/main.rs b/rom/dev/tools/test-rt/src/main.rs index 8acd64a7eb..9aef54b3f0 100644 --- a/rom/dev/tools/test-rt/src/main.rs +++ b/rom/dev/tools/test-rt/src/main.rs @@ -25,6 +25,17 @@ mod print; #[cfg(feature = "std")] pub fn main() {} +// Dummy RO data to max out FW image size. +static PAD: [u32; 26778] = { + let mut result = [0xba5eba11_u32; 26778]; + let mut i = 0; + while i < result.len() { + result[i] = result[i].wrapping_add(i as u32); + i += 1; + } + result +}; + const BANNER: &str = r#" ____ _ _ _ ____ _____ / ___|__ _| (_)_ __ | |_ _ __ __ _ | _ \_ _| @@ -38,6 +49,10 @@ const BANNER: &str = r#" pub extern "C" fn rt_entry() -> ! { cprintln!("{}", BANNER); + for (x, item) in PAD.iter().enumerate() { + cprint!("PAD[{}] = 0x{:08X}", x, *item); + } + caliptra_drivers::ExitCtrl::exit(0) }