[sw/silicon_creator] Refactor mask_rom_boot() to prioritize newer ROM_EXT
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/mask_rom/mask_rom.c b/sw/device/silicon_creator/mask_rom/mask_rom.c
index 775b3f6..50ed8c7 100644
--- a/sw/device/silicon_creator/mask_rom/mask_rom.c
+++ b/sw/device/silicon_creator/mask_rom/mask_rom.c
@@ -32,6 +32,10 @@
// sec_mmio requires this symbol. For the actual target, we need to define a
// memory region to share the data with ROM_EXT.
sec_mmio_ctx_t sec_mmio_ctx;
+// In-memory copy of the ePMP register configuration.
+epmp_state_t epmp;
+// Life cycle state of the chip.
+lifecycle_state_t lc_state = kLcStateProd;
static inline rom_error_t mask_rom_irq_error(void) {
uint32_t mcause;
@@ -50,6 +54,112 @@
return kErrorInterrupt + mcause;
}
+/**
+ * Performs once-per-boot initialization of mask ROM modules and peripherals.
+ */
+static void mask_rom_init(void) {
+ sec_mmio_init(shutdown_finalize);
+ // Initialize the shutdown policy according to lifecycle state.
+ lc_state = lifecycle_state_get();
+ shutdown_init(lc_state);
+ // Initiaize in-memory copy of the ePMP register configuration.
+ mask_rom_epmp_state_init(&epmp);
+ // Initialize pinmux configuration so we can use the UART.
+ pinmux_init();
+ // Configure UART0 as stdout.
+ uart_init(kUartNCOValue);
+ base_set_stdout((buffer_sink_t){
+ .data = NULL,
+ .sink = uart_sink,
+ });
+ // TODO: Clean device state based on reset reason (chip-specific startup).
+ // TODO: Bootstrap.
+}
+
+/**
+ * Verifies a ROM_EXT.
+ *
+ * This function performs bounds checks on the fields of the manifest, checks
+ * its `identifier` and `security_version` fields, and verifies its signature.
+ *
+ * @param Manifest of the ROM_EXT to be verified.
+ * @return Result of the operation.
+ */
+static rom_error_t mask_rom_verify(const manifest_t *manifest) {
+ RETURN_IF_ERROR(boot_policy_manifest_check(manifest));
+
+ const sigverify_rsa_key_t *key;
+ RETURN_IF_ERROR(sigverify_rsa_key_get(
+ sigverify_rsa_key_id_get(&manifest->modulus), lc_state, &key));
+
+ // TODO(#5956): Manifest usage constraints.
+ manifest_signed_region_t signed_region = manifest_signed_region_get(manifest);
+ RETURN_IF_ERROR(sigverify_rsa_verify(signed_region.start,
+ signed_region.length,
+ &manifest->signature, key, lc_state));
+ return kErrorOk;
+}
+
+/**
+ * Boots a ROM_EXT.
+ *
+ * Note: This function should not return under normal conditions. Any returns
+ * from this function must result in shutdown.
+ *
+ * @param manifest Manifest of the ROM_EXT to boot.
+ * @return rom_error_t Result of the operation.
+ */
+static rom_error_t mask_rom_boot(const manifest_t *manifest) {
+ RETURN_IF_ERROR(keymgr_check_state(kKeymgrStateReset));
+ keymgr_set_next_stage_inputs(&manifest->binding_value,
+ manifest->max_key_version);
+
+ // Unlock execution of ROM_EXT executable code (text) sections.
+ RETURN_IF_ERROR(epmp_state_check(&epmp));
+ mask_rom_epmp_unlock_rom_ext_rx(&epmp, manifest_code_region_get(manifest));
+ RETURN_IF_ERROR(epmp_state_check(&epmp));
+
+ // Jump to ROM_EXT entry point.
+ uintptr_t entry_point = manifest_entry_point_get(manifest);
+ base_printf("rom_ext_entry: %p\r\n", entry_point);
+ ((rom_ext_entry_point *)entry_point)();
+
+ return kErrorMaskRomBootFailed;
+}
+
+/**
+ * Attempts to boot ROM_EXTs in the order given by the boot policy module.
+ *
+ * @return Result of the last attempt.
+ */
+static rom_error_t mask_rom_try_boot(void) {
+ boot_policy_manifests_t manifests = boot_policy_manifests_get();
+ rom_error_t error = kErrorMaskRomBootFailed;
+ for (size_t i = 0; i < ARRAYSIZE(manifests.ordered); ++i) {
+ error = mask_rom_verify(manifests.ordered[i]);
+ if (error != kErrorOk) {
+ continue;
+ }
+ // Boot fails if a verified ROM_EXT cannot be booted.
+ RETURN_IF_ERROR(mask_rom_boot(manifests.ordered[i]));
+ // `mask_rom_boot()` should never return `kErrorOk`, but if it does
+ // we must shut down the chip instead of trying the next ROM_EXT.
+ return kErrorMaskRomBootFailed;
+ }
+ return error;
+}
+
+void mask_rom_main(void) {
+ mask_rom_init();
+
+ // TODO(#7894): What (if anything) should we print at startup?
+ base_printf("OpenTitan: \"version-tag\"\r\n");
+ base_printf("lc_state: %s\r\n", lifecycle_state_name[lc_state]);
+
+ rom_error_t error = mask_rom_try_boot();
+ shutdown_finalize(error);
+}
+
void mask_rom_interrupt_handler(void) {
shutdown_finalize(mask_rom_irq_error());
}
@@ -62,156 +172,3 @@
void mask_rom_nmi_handler(void)
__attribute__((alias("mask_rom_interrupt_handler")));
-
-rom_error_t mask_rom_boot(void) {
- // Initialize the shutdown policy according to lifecycle state.
- lifecycle_state_t lc_state = lifecycle_state_get();
- shutdown_init(lc_state);
-
- // Initiaize shadow copy of the ePMP register configuration.
- epmp_state_t epmp;
- mask_rom_epmp_state_init(&epmp);
-
- // Initialize pinmux configuration so we can use the UART.
- pinmux_init();
-
- // Configure UART0 as stdout.
- uart_init(kUartNCOValue);
- base_set_stdout((buffer_sink_t){
- .data = NULL,
- .sink = uart_sink,
- });
-
- // FIXME: what (if anything) should we print at startup?
- base_printf("OpenTitan: \"version-tag\"\r\n");
- base_printf("lc_state: %s\r\n", lifecycle_state_name[lc_state]);
-
- // boot_reason = read_boot_reason(); // Boot Policy Module
-
- // Clean Device State Part 2.
- // See "Cleaning Device State" Below.
- // clean_device_state_part_2(boot_reason); // Chip-Specific Startup Module
-
- // Chip-specific startup functionality (NOTE: we expect this portion of
- // initialization to be done in assembly before C runtime init. Delete
- // this segment of comments & pseudo-code when done).
- // **Open Q:** Proprietary Software Strategy.
- // - Clocks
- // - AST / Entropy.
- // - Flash
- // - Fuses
- // chip_specific_startup(); // Chip-Specific Startup Module
-
- // Manufacturing boot-strapping intervention.
- // **Open Q:** How does the Mask ROM deal with chip recovery?
- // Tentative answer: recovery is performed by ROM_EXT.
- // **Open Q:** Pin Strapping Configuration.
- // manufacturing_boot_strap(boot_policy, boot_reason); // Bootstrap Module
-
- // Read Boot Policy for ROM_EXTs from flash (2.b)
- // boot_policy = read_boot_policy(boot_reason); // Boot Policy Module
-
- // Determine which ROM_EXT slot is prioritised (2.b, 2.c.i)
- // for ( current_rom_ext_manifest in rom_ext_manifests_to_try(boot_policy) ) {
- // // Boot Policy Module
- while (true) {
- // Check ROM_EXT Manifest (2.c.ii)
- // **Open Q:** Integration with Secure Boot Hardware
- // - Header Format (ROM_EXT Manifest Module)
- // - **Open Q**: ROM_EXT Anti-rollback (??)
- // if (!check_rom_ext_manifest(current_rom_ext_manifest)) {
- // // Manifest Failure (check Boot Policy)
- // if (try_next_on_manifest_failed(boot_policy)) // Boot Policy Module
- // continue
- // else
- // break
- //}
-
- const manifest_t *manifest = boot_policy_manifests_get().ordered[0];
- const sigverify_rsa_key_t *key;
- RETURN_IF_ERROR(boot_policy_manifest_check(manifest));
- manifest_signed_region_t signed_region =
- manifest_signed_region_get(manifest);
- RETURN_IF_ERROR(sigverify_rsa_key_get(
- sigverify_rsa_key_id_get(&manifest->modulus), lc_state, &key));
- RETURN_IF_ERROR(sigverify_rsa_verify(signed_region.start,
- signed_region.length,
- &manifest->signature, key, lc_state));
-
- // // Manifest Failure (check Boot Policy)
- // // **Open Q:** Does this need different logic to the check after
- // // `check_rom_ext_manifest`?
- // if (try_next_on_manifest_failed(boot_policy)) // Boot Policy Module
- // continue
- // else
- // break
- //}
-
- // Update Boot Policy on Successful Signature
- // **Open Q:** Does this ensure ROM_EXT Anti-rollback is updated?
- // update_next_boot_policy(boot_policy, current_rom_ext_manifest); // Boot
- // Policy Module
-
- // Beyond this point, you know `current_rom_ext_manifest` is valid and the
- // signature has been authenticated.
- //
- // The Mask ROM now has to do various things to prepare to execute the
- // current ROM_EXT. Most of this is initializing identities, keys, and
- // potentially locking down some hardware, before jumping to ROM_EXT.
- //
- // If any of these steps fail, we've probably left the hardware in an
- // invalid state and should just reboot (because it may not be possible to
- // undo the changes, for instance to write-enable bits).
-
- // CreatorRootKey (2.c.iv)
- // - This is only allowed to be done if we have verified the signature on
- // the current ROM_EXT.
- RETURN_IF_ERROR(keymgr_check_state(kKeymgrStateReset));
- keymgr_set_next_stage_inputs(&manifest->binding_value,
- manifest->max_key_version);
-
- // Lock down Peripherals based on descriptors in ROM_EXT manifest.
- // - This does not cover key-related lockdown, which is done in
- // `derive_and_lock_creator_root_key_inputs`.
- // peripheral_lockdown(current_rom_ext_manifest); // Lockdown Module
-
- // PMP Region for ROM_EXT (2.c.v)
- // **Open Q:** Integration with Secure Boot Hardware
- // **Open Q:** Do we need to prevent access to Mask ROM after final jump?
- // pmp_unlock_rom_ext(); // Hardened Jump Module.
-
- // Transfer Execution to ROM_EXT (2.c.vi)
- // **Open Q:** Integration with Secure Boot Hardware
- // **Open Q:** Accumulated measurements to tie manifest to hardware config.
- // if (!final_jump_to_rom_ext(current_rom_ext_manifest)) { // Hardened Jump
- // Module
- if (true) {
- // Unlock execution of ROM_EXT executable code (text) sections.
- RETURN_IF_ERROR(epmp_state_check(&epmp));
- mask_rom_epmp_unlock_rom_ext_rx(&epmp,
- manifest_code_region_get(manifest));
- RETURN_IF_ERROR(epmp_state_check(&epmp));
-
- // Jump to ROM_EXT entry point.
- uintptr_t entry_point = manifest_entry_point_get(manifest);
- base_printf("rom_ext_entry: %p\r\n", entry_point);
- ((rom_ext_entry_point *)entry_point)();
- // NOTE: never expecting a return, but if something were to go wrong
- // in the real `jump` implementation, we need to enter a failure case.
-
- // Boot Failure (no policy check)
- // - Because we may have locked some write-enable bits that any following
- // manifest cannot change if it needs to, we have to just reboot here.
- // boot_failed(boot_policy, current_rom_ext_manifest); // Boot Policy
- // Module
- }
- }
-
- return kErrorMaskRomBootFailed;
-}
-
-void mask_rom_main(void) {
- sec_mmio_init(shutdown_finalize);
- rom_error_t error = mask_rom_boot();
- shutdown_finalize(error);
-}