Repository: chipsalliance/caliptra-sw
Pull request #451 (2023-06-30 19:05:57)

[test] Update Reset flow integration tests


Patch:
diff --git a/rom/dev/src/flow/update_reset.rs b/rom/dev/src/flow/update_reset.rs
index 10140c9d..fd0c178c 100644
--- a/rom/dev/src/flow/update_reset.rs
+++ b/rom/dev/src/flow/update_reset.rs
@@ -147,7 +147,7 @@ impl UpdateResetFlow {
         //Call the complete here to reset the execute bit
         txn.complete(true)?;
 
-        // Drop the tranaction and release the Mailbox lock after the image
+        // Drop the transaction and release the Mailbox lock after the image
         // has been successfully verified and loaded in memory
         drop(txn);
 


Test patch:
diff --git a/rom/dev/doc/test-coverage/test-coverage.md b/rom/dev/doc/test-coverage/test-coverage.md
index 530a0fae..aa8857e4 100644
--- a/rom/dev/doc/test-coverage/test-coverage.md
+++ b/rom/dev/doc/test-coverage/test-coverage.md
@@ -47,7 +47,8 @@ Test Name | ROM Stage | Description | ROM Error Code
 **cert_test** | DICE Cert | <Placeholder> | N/A
 **cert_test_with_custom_dates** | DICE Cert | <Placeholder> | N/A
 <br><br>
-# **IDEVID Integration Tests**
+# **COLD BOOT Tests**
+## **IDEVID Integration Tests**
 Test Name | ROM Stage | Description | ROM Error Code
 ---|---|---|---
 **test_idev_subj_key_id_algo** | DICE - IDEVID | Tests with X509KeyIdAlgo::[SHA1/SHA256/SHA384/Fuse] for generating  Subject Key Identifier | N/A
@@ -61,16 +62,24 @@ Test Name | ROM Stage | Description | ROM Error Code
 **test_pcr_log** | FW Donwloader |  Checks if PCR log entries are correctly logged to DCCM  | N/A
 **ttest_fuse_log** | FW Donwloader |  Checks if Fuse log entries are correctly logged to DCCM  | N/A
 <br><br>
-# **FMCALIAS Integration Tests**
+## **FMCALIAS Integration Tests**
 Test Name | ROM Stage | Description | ROM Error Code
 ---|---|---|---
 **test_fht_info** | DICE - FMCALIAS | Checks if entries are correctly added in Firmware Handoff table | N/A
 <br><br>
-# **DICE E2E Integration Tests**
+## **DICE E2E Integration Tests**
 Test Name | ROM Stage | Description | ROM Error Code
 ---|---|---|---
 **test_status_reporting** | All layers | Checks if boot statuses are correctly reported | N/A
 <br><br>
+# **Update Reset Tests**
+Test Name |  Description | ROM Error Code
+---|---|---
+**test_update_reset_success** | Tests successful Update Reset flow  | N/A
+**test_update_reset_no_mailbox_cmd** | Tests update reset flow by not providing firmware image  | ROM_UPDATE_RESET_FLOW_MAILBOX_ACCESS_FAILURE
+**test_update_reset_non_fw_load_cmd** | Tests update reset flow by providing a non-fw load Mailbox command  | ROM_UPDATE_RESET_FLOW_INVALID_FIRMWARE_COMMAND
+**test_update_reset_verify_image_failure** | Tests update reset flow by providing non-compliant fw image  | IMAGE_VERIFIER_ERR_MANIFEST_MARKER_MISMATCH
+<br><br>
 # **Mailbox Tests**
 Test Name | ROM Stage | Description | ROM Error Code
 ---|---|---|---
diff --git a/rom/dev/tests/test_image_validation.rs b/rom/dev/tests/test_image_validation.rs
index 7212b1dd..dfb6863b 100644
--- a/rom/dev/tests/test_image_validation.rs
+++ b/rom/dev/tests/test_image_validation.rs
@@ -1339,6 +1339,11 @@ fn cert_test_with_custom_dates() {
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
 
+    hw.step_until_output_contains("[exit] Launching FMC")
+        .unwrap();
+
+    hw.mailbox_execute(0x1000_0001, &[]).unwrap();
+
     let result = hw.copy_output_until_exit_success(&mut output);
     assert!(result.is_ok());
     let output = String::from_utf8_lossy(&output);
@@ -1402,6 +1407,11 @@ fn cert_test() {
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
 
+    hw.step_until_output_contains("[exit] Launching FMC")
+        .unwrap();
+
+    hw.mailbox_execute(0x1000_0001, &[]).unwrap();
+
     let result = hw.copy_output_until_exit_success(&mut output);
     assert!(result.is_ok());
     let output = String::from_utf8_lossy(&output);
diff --git a/rom/dev/tests/test_update_reset.rs b/rom/dev/tests/test_update_reset.rs
new file mode 100644
index 00000000..2db706ee
--- /dev/null
+++ b/rom/dev/tests/test_update_reset.rs
@@ -0,0 +1,208 @@
+// Licensed under the Apache-2.0 license
+
+use caliptra_builder::{FwId, ImageOptions, APP_WITH_UART, ROM_WITH_UART};
+use caliptra_error::CaliptraError;
+use caliptra_hw_model::{BootParams, Fuses, HwModel, InitParams, SecurityState};
+pub mod helpers;
+
+const TEST_FMC_CMD_RESET_FOR_UPDATE: u32 = 0x1000_0004;
+
+#[test]
+fn test_update_reset_success() {
+    pub const TEST_FMC_WITH_UART: FwId = FwId {
+        crate_name: "caliptra-rom-test-fmc",
+        bin_name: "caliptra-rom-test-fmc",
+        features: &["emu"],
+        workspace_dir: None,
+    };
+
+    let fuses = Fuses::default();
+    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
+    let mut hw = caliptra_hw_model::new(BootParams {
+        init_params: InitParams {
+            rom: &rom,
+            security_state: SecurityState::from(fuses.life_cycle as u32),
+            ..Default::default()
+        },
+        fuses,
+        ..Default::default()
+    })
+    .unwrap();
+
+    let image_bundle = caliptra_builder::build_and_sign_image(
+        &TEST_FMC_WITH_UART,
+        &APP_WITH_UART,
+        ImageOptions::default(),
+    )
+    .unwrap();
+
+    hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+        .unwrap();
+
+    hw.step_until_output_contains("[exit] Launching FMC")
+        .unwrap();
+
+    hw.mailbox_execute(TEST_FMC_CMD_RESET_FOR_UPDATE, &[])
+        .unwrap();
+
+    hw.step_until_output_contains("[update-reset] ++").unwrap();
+
+    hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+        .unwrap();
+
+    hw.step_until_exit_success().unwrap();
+}
+
+#[test]
+fn test_update_reset_no_mailbox_cmd() {
+    pub const TEST_FMC_WITH_UART: FwId = FwId {
+        crate_name: "caliptra-rom-test-fmc",
+        bin_name: "caliptra-rom-test-fmc",
+        features: &["emu"],
+        workspace_dir: None,
+    };
+
+    let fuses = Fuses::default();
+    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
+    let mut hw = caliptra_hw_model::new(BootParams {
+        init_params: InitParams {
+            rom: &rom,
+            security_state: SecurityState::from(fuses.life_cycle as u32),
+            ..Default::default()
+        },
+        fuses,
+        ..Default::default()
+    })
+    .unwrap();
+
+    let image_bundle = caliptra_builder::build_and_sign_image(
+        &TEST_FMC_WITH_UART,
+        &APP_WITH_UART,
+        ImageOptions::default(),
+    )
+    .unwrap();
+
+    hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+        .unwrap();
+
+    hw.step_until_output_contains("[exit] Launching FMC")
+        .unwrap();
+
+    hw.mailbox_execute(TEST_FMC_CMD_RESET_FOR_UPDATE, &[])
+        .unwrap();
+
+    hw.step_until_output_contains("[update-reset] ++").unwrap();
+
+    // No command in the mailbox.
+    hw.soc_mbox().cmd().write(|_| 0);
+    hw.step_until(|m| m.soc_ifc().cptra_fw_error_non_fatal().read() != 0);
+
+    let _ = hw.mailbox_execute(0xDEADBEEF, &[]);
+    hw.step_until_exit_success().unwrap();
+
+    assert_eq!(
+        hw.soc_ifc().cptra_fw_error_non_fatal().read(),
+        CaliptraError::ROM_UPDATE_RESET_FLOW_MAILBOX_ACCESS_FAILURE.into()
+    );
+}
+
+#[test]
+fn test_update_reset_non_fw_load_cmd() {
+    pub const TEST_FMC_WITH_UART: FwId = FwId {
+        crate_name: "caliptra-rom-test-fmc",
+        bin_name: "caliptra-rom-test-fmc",
+        features: &["emu"],
+        workspace_dir: None,
+    };
+
+    let fuses = Fuses::default();
+    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
+    let mut hw = caliptra_hw_model::new(BootParams {
+        init_params: InitParams {
+            rom: &rom,
+            security_state: SecurityState::from(fuses.life_cycle as u32),
+            ..Default::default()
+        },
+        fuses,
+        ..Default::default()
+    })
+    .unwrap();
+
+    let image_bundle = caliptra_builder::build_and_sign_image(
+        &TEST_FMC_WITH_UART,
+        &APP_WITH_UART,
+        ImageOptions::default(),
+    )
+    .unwrap();
+
+    hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+        .unwrap();
+
+    hw.step_until_output_contains("[exit] Launching FMC")
+        .unwrap();
+
+    hw.mailbox_execute(TEST_FMC_CMD_RESET_FOR_UPDATE, &[])
+        .unwrap();
+
+    hw.step_until_output_contains("[update-reset] ++").unwrap();
+
+    // Send a non-fw load command
+    let _ = hw.mailbox_execute(0xDEADBEEF, &[]);
+    hw.step_until_exit_success().unwrap();
+
+    assert_eq!(
+        hw.soc_ifc().cptra_fw_error_non_fatal().read(),
+        CaliptraError::ROM_UPDATE_RESET_FLOW_INVALID_FIRMWARE_COMMAND.into()
+    );
+}
+
+#[test]
+fn test_update_reset_verify_image_failure() {
+    pub const TEST_FMC_WITH_UART: FwId = FwId {
+        crate_name: "caliptra-rom-test-fmc",
+        bin_name: "caliptra-rom-test-fmc",
+        features: &["emu"],
+        workspace_dir: None,
+    };
+
+    let fuses = Fuses::default();
+    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
+    let mut hw = caliptra_hw_model::new(BootParams {
+        init_params: InitParams {
+            rom: &rom,
+            security_state: SecurityState::from(fuses.life_cycle as u32),
+            ..Default::default()
+        },
+        fuses,
+        ..Default::default()
+    })
+    .unwrap();
+
+    let image_bundle = caliptra_builder::build_and_sign_image(
+        &TEST_FMC_WITH_UART,
+        &APP_WITH_UART,
+        ImageOptions::default(),
+    )
+    .unwrap();
+
+    hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+        .unwrap();
+
+    hw.step_until_output_contains("[exit] Launching FMC")
+        .unwrap();
+
+    hw.mailbox_execute(TEST_FMC_CMD_RESET_FOR_UPDATE, &[])
+        .unwrap();
+
+    hw.step_until_output_contains("[update-reset] ++").unwrap();
+
+    // Upload invalid manifest
+    let _ = hw.upload_firmware(&[0u8; 4]);
+
+    hw.step_until_exit_success().unwrap();
+
+    assert_eq!(
+        hw.soc_ifc().cptra_fw_error_non_fatal().read(),
+        CaliptraError::IMAGE_VERIFIER_ERR_MANIFEST_MARKER_MISMATCH.into()
+    );
+}
diff --git a/rom/dev/tools/test-fmc/src/main.rs b/rom/dev/tools/test-fmc/src/main.rs
index af635a1b..ed42618a 100644
--- a/rom/dev/tools/test-fmc/src/main.rs
+++ b/rom/dev/tools/test-fmc/src/main.rs
@@ -22,6 +22,8 @@ extern "C" {
     static mut FHT_ORG: u8;
 }
 
+use core::ptr;
+
 use caliptra_common::FirmwareHandoffTable;
 use caliptra_common::{FuseLogEntry, FuseLogEntryId};
 use caliptra_common::{PcrLogEntry, PcrLogEntryId};
@@ -58,8 +60,6 @@ pub extern "C" fn fmc_entry() -> ! {
     let fht = FirmwareHandoffTable::read_from(slice).unwrap();
     assert!(fht.is_valid());
 
-    create_certs();
-
     process_mailbox_commands();
 
     caliptra_drivers::ExitCtrl::exit(0)
@@ -111,7 +111,7 @@ fn fmc_panic(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
 
-fn create_certs() {
+fn create_certs(mbox: &caliptra_registers::mbox::RegisterBlock<RealMmioMut>) {
     //
     // Create LDEVID cert.
     //
@@ -166,6 +166,8 @@ fn create_certs() {
             .unwrap();
     let _cert_len = builder.build(&mut cert).unwrap();
     cprint_slice_ref!("[fmc] FMCALIAS cert", &cert[.._cert_len]);
+
+    mbox.status().write(|w| w.status(|w| w.cmd_complete()));
 }
 
 fn copy_tbs(tbs: &mut [u8], ldevid_tbs: bool) {
@@ -210,7 +212,7 @@ fn process_mailbox_commands() {
             read_pcr_log(&mbox);
         }
         0x1000_0001 => {
-            // TODO: Generate certs
+            create_certs(&mbox);
         }
         0x1000_0002 => {
             read_fuse_log(&mbox);
@@ -218,10 +220,21 @@ fn process_mailbox_commands() {
         0x1000_0003 => {
             read_fht(&mbox);
         }
+        0x1000_0004 => {
+            trigger_update_reset(&mbox);
+        }
         _ => {}
     }
 }
 
+fn trigger_update_reset(mbox: &caliptra_registers::mbox::RegisterBlock<RealMmioMut>) {
+    mbox.status().write(|w| w.status(|w| w.cmd_complete()));
+    const STDOUT: *mut u32 = 0x3003_0624 as *mut u32;
+    unsafe {
+        ptr::write_volatile(STDOUT, 1_u32);
+    }
+}
+
 fn read_pcr_log(mbox: &caliptra_registers::mbox::RegisterBlock<RealMmioMut>) {
     let mut pcr_entry_count = 0;
     loop {