Repository: chipsalliance/caliptra-sw
Pull request #461 (2023-07-07 03:37:42)

FMC : report boot status
Report boot status in FMC.


Patch:
diff --git a/fmc/src/boot_status.rs b/fmc/src/boot_status.rs
new file mode 100644
index 00000000..12b56418
--- /dev/null
+++ b/fmc/src/boot_status.rs
@@ -0,0 +1,23 @@
+// Licensed under the Apache-2.0 license
+use core::convert::From;
+const RTALIAS_BOOT_STATUS_BASE: u32 = 0x400;
+
+/// Statuses used by ROM to log dice derivation progress.
+#[repr(u32)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum FmcBootStatus {
+    // RtAlias Statuses
+    RtAliasDeriveCdiComplete = RTALIAS_BOOT_STATUS_BASE,
+    RtAliasKeyPairDerivationComplete = RTALIAS_BOOT_STATUS_BASE + 1,
+    RtAliasSubjIdSnGenerationComplete = RTALIAS_BOOT_STATUS_BASE + 2,
+    RtAliasSubjKeyIdGenerationComplete = RTALIAS_BOOT_STATUS_BASE + 3,
+    RtAliasCertSigGenerationComplete = RTALIAS_BOOT_STATUS_BASE + 4,
+    RtAliasDerivationComplete = RTALIAS_BOOT_STATUS_BASE + 5,
+}
+
+impl From<FmcBootStatus> for u32 {
+    /// Converts to this type from the input type.
+    fn from(status: FmcBootStatus) -> u32 {
+        status as u32
+    }
+}
diff --git a/fmc/src/flow/rt_alias.rs b/fmc/src/flow/rt_alias.rs
index 07040350..3fc08ed8 100644
--- a/fmc/src/flow/rt_alias.rs
+++ b/fmc/src/flow/rt_alias.rs
@@ -18,12 +18,14 @@ use crate::flow::tci::Tci;
 use crate::flow::x509::X509;
 use crate::flow::{KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY};
 use crate::fmc_env::FmcEnv;
+use crate::FmcBootStatus;
 use crate::HandOff;
 use caliptra_common::cprintln;
 use caliptra_common::crypto::Ecc384KeyPair;
 use caliptra_common::HexBytes;
 use caliptra_drivers::{
-    okref, CaliptraError, CaliptraResult, Hmac384Data, Hmac384Key, KeyId, KeyReadArgs,
+    okref, report_boot_status, CaliptraError, CaliptraResult, Hmac384Data, Hmac384Key, KeyId,
+    KeyReadArgs,
 };
 use caliptra_x509::{NotAfter, NotBefore, RtAliasCertTbs, RtAliasCertTbsParams};
 
@@ -48,6 +50,7 @@ impl RtAliasLayer {
         cprintln!("[alias rt] Store in in slot 0x{:x}", KEY_ID_RT_CDI as u8);
         // Derive CDI
         let _ = *okref(&Self::derive_cdi(env, hand_off, input, KEY_ID_RT_CDI))?;
+        report_boot_status(FmcBootStatus::RtAliasDeriveCdiComplete as u32);
         cprintln!("[alias rt] Derive Key Pair");
         cprintln!(
             "[alias rt] Store priv key in slot 0x{:x}",
@@ -67,13 +70,17 @@ impl RtAliasLayer {
         // Derive DICE Key Pair from CDI
         let key_pair = Self::derive_key_pair(env, KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY)?;
         cprintln!("[alias rt] Derive Key Pair - Done");
+        report_boot_status(FmcBootStatus::RtAliasKeyPairDerivationComplete as u32);
 
         // Generate the Subject Serial Number and Subject Key Identifier.
         //
         // This information will be used by next DICE Layer while generating
         // certificates
         let subj_sn = X509::subj_sn(env, &key_pair.pub_key)?;
+        report_boot_status(FmcBootStatus::RtAliasSubjIdSnGenerationComplete.into());
+
         let subj_key_id = X509::subj_key_id(env, &key_pair.pub_key)?;
+        report_boot_status(FmcBootStatus::RtAliasSubjKeyIdGenerationComplete.into());
 
         // Generate the output for next layer
         let output = DiceOutput {
@@ -101,6 +108,7 @@ impl RtAliasLayer {
         match Self::dice_input_from_hand_off(hand_off, env) {
             Ok(input) => {
                 let out = Self::derive(env, hand_off, &input)?;
+                report_boot_status(crate::FmcBootStatus::RtAliasDerivationComplete as u32);
                 hand_off.update(out)
             }
             _ => Err(CaliptraError::FMC_RT_ALIAS_DERIVE_FAILURE),
@@ -178,6 +186,7 @@ impl RtAliasLayer {
         // Permute CDI from FMC TCI
         let data = Hmac384Data::Slice(&tci);
         let cdi = Crypto::hmac384_mac(env, &key, &data, cdi)?;
+        report_boot_status(FmcBootStatus::RtAliasDeriveCdiComplete as u32);
         Ok(cdi)
     }
 
@@ -287,6 +296,8 @@ impl RtAliasLayer {
         //  Copy TBS to DCCM.
         Self::copy_tbs(tbs.tbs())?;
 
+        report_boot_status(FmcBootStatus::RtAliasCertSigGenerationComplete as u32);
+
         Ok(())
     }
 
diff --git a/fmc/src/main.rs b/fmc/src/main.rs
index fdd2240e..4c72903e 100644
--- a/fmc/src/main.rs
+++ b/fmc/src/main.rs
@@ -17,10 +17,12 @@ use core::hint::black_box;
 
 use caliptra_common::cprintln;
 use caliptra_drivers::{report_fw_error_non_fatal, Mailbox};
+mod boot_status;
 mod flow;
 pub mod fmc_env;
 mod hand_off;
 
+pub use boot_status::FmcBootStatus;
 use caliptra_cpu::TrapRecord;
 use hand_off::HandOff;
 
diff --git a/hw-model/src/lib.rs b/hw-model/src/lib.rs
index 82278826..61793f7b 100644
--- a/hw-model/src/lib.rs
+++ b/hw-model/src/lib.rs
@@ -482,6 +482,41 @@ pub trait HwModel {
         Ok(())
     }
 
+    fn step_until_boot_status(
+        &mut self,
+        expected_status_u32: u32,
+        ignore_intermediate_status: bool,
+    ) {
+        // Since the boot takes less than 20M cycles, we know something is wrong if
+        // we're stuck at the same state for that duration.
+        const MAX_WAIT_CYCLES: u32 = 20_000_000;
+
+        let mut cycle_count = 0u32;
+        let initial_boot_status_u32 = self.soc_ifc().cptra_boot_status().read();
+        loop {
+            let actual_status_u32 = self.soc_ifc().cptra_boot_status().read();
+            if expected_status_u32 == actual_status_u32 {
+                break;
+            }
+
+            if !ignore_intermediate_status && actual_status_u32 != initial_boot_status_u32 {
+                panic!(
+                    "Expected the next boot_status to be  \
+                    ({expected_status_u32}), but status changed from \
+                    {initial_boot_status_u32} to {actual_status_u32})"
+                );
+            }
+            self.step();
+            cycle_count += 1;
+            if cycle_count >= MAX_WAIT_CYCLES {
+                panic!(
+                    "Expected boot_status to be  \
+                    ({expected_status_u32}), but was stuck at ({actual_status_u32})"
+                );
+            }
+        }
+    }
+
     /// A register block that can be used to manipulate the soc_ifc peripheral
     /// over the simulated SoC->Caliptra APB bus.
     fn soc_ifc(&mut self) -> caliptra_registers::soc_ifc::RegisterBlock<BusMmio<Self::TBus<'_>>> {


Test patch:
diff --git a/fmc/tests/test_rtalias.rs b/fmc/tests/test_rtalias.rs
new file mode 100644
index 00000000..26335983
--- /dev/null
+++ b/fmc/tests/test_rtalias.rs
@@ -0,0 +1,49 @@
+// Licensed under the Apache-2.0 license
+use caliptra_builder::{FwId, ImageOptions, FMC_WITH_UART, ROM_WITH_UART};
+use caliptra_hw_model::{BootParams, HwModel, InitParams};
+
+const RT_ALIAS_DERIVED_CDI_COMPLETE: u32 = 0x400;
+const RT_ALIAS_KEY_PAIR_DERIVATION_COMPLETE: u32 = 0x401;
+const RT_ALIAS_SUBJ_ID_SN_GENERATION_COMPLETE: u32 = 0x402;
+const RT_ALIAS_SUBJ_KEY_ID_GENERATION_COMPLETE: u32 = 0x403;
+const RT_ALIAS_CERT_SIG_GENERATION_COMPLETE: u32 = 0x404;
+const RT_ALIAS_DERIVATION_COMPLETE: u32 = 0x405;
+
+#[test]
+fn test_boot_status_reporting() {
+    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
+
+    pub const MOCK_RT_WITH_UART: FwId = FwId {
+        crate_name: "caliptra-fmc-mock-rt",
+        bin_name: "caliptra-fmc-mock-rt",
+        features: &["emu"],
+        workspace_dir: None,
+    };
+
+    let image = caliptra_builder::build_and_sign_image(
+        &FMC_WITH_UART,
+        &MOCK_RT_WITH_UART,
+        ImageOptions::default(),
+    )
+    .unwrap();
+
+    let mut hw = caliptra_hw_model::new(BootParams {
+        init_params: InitParams {
+            rom: &rom,
+            ..Default::default()
+        },
+        fw_image: Some(&image.to_bytes().unwrap()),
+        ..Default::default()
+    })
+    .unwrap();
+
+    hw.step_until_boot_status(RT_ALIAS_DERIVED_CDI_COMPLETE, true);
+    hw.step_until_boot_status(RT_ALIAS_KEY_PAIR_DERIVATION_COMPLETE, true);
+    hw.step_until_boot_status(RT_ALIAS_SUBJ_ID_SN_GENERATION_COMPLETE, true);
+    hw.step_until_boot_status(RT_ALIAS_SUBJ_KEY_ID_GENERATION_COMPLETE, true);
+    hw.step_until_boot_status(RT_ALIAS_CERT_SIG_GENERATION_COMPLETE, true);
+    hw.step_until_boot_status(RT_ALIAS_DERIVATION_COMPLETE, true);
+
+    let mut output = vec![];
+    hw.copy_output_until_exit_success(&mut output).unwrap();
+}