test_rom: revamp & track opentitan api's

- use uintptr_t instead of mmio_region_t to track opentitan

Bypass-Presubmit-Reason: verified as part of topic

Change-Id: I0de57237ee0b8af1a1732cadfd982e7911a3ca3d
diff --git a/sw/device/examples/hello_world_multicore/hello_world_multicore_sc_loaders_extflash.c b/sw/device/examples/hello_world_multicore/hello_world_multicore_sc_loaders_extflash.c
index 765e3f5..33ac8d7 100644
--- a/sw/device/examples/hello_world_multicore/hello_world_multicore_sc_loaders_extflash.c
+++ b/sw/device/examples/hello_world_multicore/hello_world_multicore_sc_loaders_extflash.c
@@ -33,11 +33,8 @@
 }
 
 void load_init(void) {
-  const mmio_region_t spi_host_addr =
-      mmio_region_from_addr(TOP_MATCHA_SPI_HOST0_BASE_ADDR);
-  const mmio_region_t eflash_addr =
-      mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR);
-  const mmio_region_t otp_addr =
-      mmio_region_from_addr(TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR);
+  const uintptr_t spi_host_addr = TOP_MATCHA_SPI_HOST0_BASE_ADDR;
+  const uintptr_t eflash_addr = TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR;
+  const uintptr_t otp_addr = TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR;
   spi_flash_init(spi_host_addr, eflash_addr, otp_addr);
 }
diff --git a/sw/device/lib/arch/device.h b/sw/device/lib/arch/device.h
index f9027bf..ac52fad 100644
--- a/sw/device/lib/arch/device.h
+++ b/sw/device/lib/arch/device.h
@@ -196,6 +196,6 @@
  *
  * This function is a NOP unless we are building for an FPGA.
  */
-void device_fpga_version_print(void);
+void device_fpga_version_print(uintptr_t ibex_addr);
 
 #endif  // SW_DEVICE_LIB_ARCH_DEVICE_H_
diff --git a/sw/device/lib/arch/device_sc_asic.c b/sw/device/lib/arch/device_sc_asic.c
index 00fe315..9352d65 100644
--- a/sw/device/lib/arch/device_sc_asic.c
+++ b/sw/device/lib/arch/device_sc_asic.c
@@ -61,4 +61,4 @@
 
 const bool kJitterEnabled = false;
 
-void device_fpga_version_print(void) {}
+void device_fpga_version_print(uintptr_t ibex_addr) {}
diff --git a/sw/device/lib/arch/device_sc_fpga_nexus.c b/sw/device/lib/arch/device_sc_fpga_nexus.c
index 8e66357..621cd54 100644
--- a/sw/device/lib/arch/device_sc_fpga_nexus.c
+++ b/sw/device/lib/arch/device_sc_fpga_nexus.c
@@ -62,9 +62,9 @@
 
 const bool kJitterEnabled = false;
 
-void device_fpga_version_print(void) {
+void device_fpga_version_print(uintptr_t ibex_addr) {
   // This value is guaranteed to be zero on all non-FPGA implementations.
-  uint32_t fpga = ibex_fpga_version();
+  uint32_t fpga = ibex_fpga_version(ibex_addr);
   // The cast to unsigned int stops GCC from complaining about uint32_t
   // being a `long unsigned int` while the %x specifier takes `unsigned int`.
   rom_printf("ROM:%x\r\n", (unsigned int)fpga);
diff --git a/sw/device/lib/arch/device_sim_dv.c b/sw/device/lib/arch/device_sim_dv.c
index fa5b0d1..77ec835 100644
--- a/sw/device/lib/arch/device_sim_dv.c
+++ b/sw/device/lib/arch/device_sim_dv.c
@@ -66,4 +66,4 @@
 
 const bool kJitterEnabled = false;
 
-void device_fpga_version_print(void) {}
+void device_fpga_version_print(uintptr_t ibex_addr) {}
diff --git a/sw/device/lib/arch/device_sim_verilator.c b/sw/device/lib/arch/device_sim_verilator.c
index 112b7bd..58845ce 100644
--- a/sw/device/lib/arch/device_sim_verilator.c
+++ b/sw/device/lib/arch/device_sim_verilator.c
@@ -71,4 +71,4 @@
 
 const bool kJitterEnabled = false;
 
-void device_fpga_version_print(void) {}
+void device_fpga_version_print(uintptr_t ibex_addr) {}
diff --git a/sw/device/lib/arch/device_smc_sim_dv.c b/sw/device/lib/arch/device_smc_sim_dv.c
index 477165f..4f7f0bc 100644
--- a/sw/device/lib/arch/device_smc_sim_dv.c
+++ b/sw/device/lib/arch/device_smc_sim_dv.c
@@ -63,4 +63,4 @@
 
 const bool kJitterEnabled = false;
 
-void device_fpga_version_print(void) {}
+void device_fpga_version_print(uintptr_t ibex_addr) {}
diff --git a/sw/device/lib/eflash.c b/sw/device/lib/eflash.c
index ff07bc4..6307252 100644
--- a/sw/device/lib/eflash.c
+++ b/sw/device/lib/eflash.c
@@ -25,18 +25,18 @@
 
 static dif_flash_ctrl_state_t flash_ctrl;
 
-dif_result_t eflash_init(mmio_region_t base_addr, mmio_region_t otp_addr) {
-  CHECK_DIF_OK(dif_flash_ctrl_init_state(&flash_ctrl, base_addr));
+dif_result_t eflash_init(uintptr_t base_addr, uintptr_t otp_addr) {
+  CHECK_DIF_OK(dif_flash_ctrl_init_state(&flash_ctrl, mmio_region_from_addr(base_addr)));
   flash_ctrl_init(base_addr, otp_addr);
   return kDifOk;
 }
 
-dif_result_t eflash_chip_erase(void) {
-  flash_ctrl_bank_erase_perms_set(kHardenedBoolTrue);
-  rom_error_t err_0 = flash_ctrl_data_erase(0, kFlashCtrlEraseTypeBank);
-  rom_error_t err_1 = flash_ctrl_data_erase(FLASH_CTRL_PARAM_BYTES_PER_BANK,
+dif_result_t eflash_chip_erase(uintptr_t base_addr) {
+  flash_ctrl_bank_erase_perms_set(base_addr, kHardenedBoolTrue);
+  rom_error_t err_0 = flash_ctrl_data_erase(base_addr, 0, kFlashCtrlEraseTypeBank);
+  rom_error_t err_1 = flash_ctrl_data_erase(base_addr, FLASH_CTRL_PARAM_BYTES_PER_BANK,
                                             kFlashCtrlEraseTypeBank);
-  flash_ctrl_bank_erase_perms_set(kHardenedBoolFalse);
+  flash_ctrl_bank_erase_perms_set(base_addr, kHardenedBoolFalse);
   if (err_0 != kErrorOk || err_1 != kErrorOk) {
     return kDifError;
   }
@@ -45,19 +45,19 @@
 
 // Writes 256-bytes from src to dst.
 // Take dst as a memory address, and mask off the top.
-dif_result_t eflash_write_page(const void* dst, uint8_t* src) {
+dif_result_t eflash_write_page(uintptr_t base_addr, const void* dst, uint8_t* src) {
   uint32_t flash_dst = (uint32_t)dst & ~TOP_MATCHA_EFLASH_BASE_ADDR;
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(base_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4False,
       .write = kMultiBitBool4True,
       .erase = kMultiBitBool4False,
   });
   rom_error_t err = flash_ctrl_data_write(
-      flash_dst, EFLASH_PAGE_SIZE / sizeof(uint32_t), src);
+      base_addr, flash_dst, EFLASH_PAGE_SIZE / sizeof(uint32_t), src);
   if (err != kErrorOk) {
     return kDifError;
   }
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(base_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4True,
       .write = kMultiBitBool4False,
       .erase = kMultiBitBool4False,
diff --git a/sw/device/lib/eflash.h b/sw/device/lib/eflash.h
index e4c6a2a..c43ad92 100644
--- a/sw/device/lib/eflash.h
+++ b/sw/device/lib/eflash.h
@@ -29,10 +29,10 @@
 extern "C" {
 #endif
 
-OT_WARN_UNUSED_RESULT dif_result_t eflash_init(mmio_region_t base_addr,
-                                               mmio_region_t otp_addr);
-OT_WARN_UNUSED_RESULT dif_result_t eflash_chip_erase(void);
-OT_WARN_UNUSED_RESULT dif_result_t eflash_write_page(const void* dst,
+OT_WARN_UNUSED_RESULT dif_result_t eflash_init(uintptr_t base_addr,
+                                               uintptr_t otp_addr);
+OT_WARN_UNUSED_RESULT dif_result_t eflash_chip_erase(uintptr_t base_addr);
+OT_WARN_UNUSED_RESULT dif_result_t eflash_write_page(uintptr_t base_addr, const void* dst,
                                                      uint8_t* src);
 
 #if defined(__cplusplus)
diff --git a/sw/device/lib/spi_flash.c b/sw/device/lib/spi_flash.c
index f80c508..890a1d5 100644
--- a/sw/device/lib/spi_flash.c
+++ b/sw/device/lib/spi_flash.c
@@ -26,6 +26,7 @@
 #include "sw/device/lib/testing/test_framework/check.h"
 
 static dif_spi_host_t spi_host0;
+static uintptr_t flash_ctrl_addr;
 static const int kSpiFlashBytes = (64 * 1024 * 1024);
 
 dif_result_t spi_flash_read_page(uint32_t page, uint8_t* buf) {
@@ -70,16 +71,18 @@
   return kDifOk;
 }
 
-dif_result_t spi_flash_init(mmio_region_t spi_host_addr,
-                            mmio_region_t eflash_addr, mmio_region_t otp_addr) {
-  CHECK_DIF_OK(dif_spi_host_init(spi_host_addr, &spi_host0));
+dif_result_t spi_flash_init(uintptr_t spi_host_addr,
+                            uintptr_t flash_ctrl_addr_, uintptr_t otp_addr) {
+  flash_ctrl_addr = flash_ctrl_addr_;
+
+  CHECK_DIF_OK(dif_spi_host_init(mmio_region_from_addr(spi_host_addr), &spi_host0));
   dif_spi_host_config_t config = {
       .spi_clock = kClockFreqSpiFlashHz,
       .peripheral_clock_freq_hz = kClockFreqCpuHz,
   };
   CHECK_DIF_OK(dif_spi_host_configure(&spi_host0, config));
   CHECK_DIF_OK(dif_spi_host_output_set_enabled(&spi_host0, /*enabled=*/true));
-  CHECK_DIF_OK(eflash_init(eflash_addr, otp_addr));
+  CHECK_DIF_OK(eflash_init(flash_ctrl_addr, otp_addr));
   return kDifOk;
 }
 
@@ -159,7 +162,7 @@
       (uintptr_t)addr <
           TOP_MATCHA_EFLASH_BASE_ADDR + TOP_MATCHA_EFLASH_SIZE_BYTES) {
     eflash = true;
-    CHECK_DIF_OK(eflash_chip_erase());
+    CHECK_DIF_OK(eflash_chip_erase(flash_ctrl_addr));
   };
   while (remaining > 0) {
     size_t page_used = remaining >= SPI_PAGE_SIZE ? SPI_PAGE_SIZE : remaining;
@@ -167,9 +170,9 @@
     CHECK_DIF_OK(spi_flash_read_page(bin_offset + offset, page));
     void* dst = (uint8_t*)addr + offset;
     if (eflash) {
-      CHECK_DIF_OK(eflash_write_page(dst, page));
+      CHECK_DIF_OK(eflash_write_page(flash_ctrl_addr, dst, page));
       CHECK_DIF_OK(
-          eflash_write_page(dst + EFLASH_PAGE_SIZE, page + EFLASH_PAGE_SIZE));
+          eflash_write_page(flash_ctrl_addr, dst + EFLASH_PAGE_SIZE, page + EFLASH_PAGE_SIZE));
     } else {
       if (memcpy(dst, page, page_used) != dst) {
         return kDifError;
diff --git a/sw/device/lib/spi_flash.h b/sw/device/lib/spi_flash.h
index e29c69f..3974794 100644
--- a/sw/device/lib/spi_flash.h
+++ b/sw/device/lib/spi_flash.h
@@ -30,8 +30,8 @@
 #endif
 
 /* General SPI flash related methods */
-dif_result_t spi_flash_init(mmio_region_t spi_host_addr,
-                            mmio_region_t eflash_addr, mmio_region_t otp_addr);
+dif_result_t spi_flash_init(uintptr_t spi_host_addr, uintptr_t flash_ctrl_addr,
+                            uintptr_t otp_addr);
 dif_result_t spi_flash_read_page(uint32_t page, uint8_t* buf);
 
 /* Tar filesystem related methods */
diff --git a/sw/device/lib/testing/test_rom/puppeteer.cc b/sw/device/lib/testing/test_rom/puppeteer.cc
index c9f2a57..2324ba8 100644
--- a/sw/device/lib/testing/test_rom/puppeteer.cc
+++ b/sw/device/lib/testing/test_rom/puppeteer.cc
@@ -34,12 +34,12 @@
 static dif_flash_ctrl_state_t flash_ctrl;
 static dif_spi_host spi_host0;
 
-__attribute__((warn_unused_result)) bool eflash_chip_erase(void) {
-  flash_ctrl_bank_erase_perms_set(kHardenedBoolTrue);
-  rom_error_t err_0 = flash_ctrl_data_erase(0, kFlashCtrlEraseTypeBank);
-  rom_error_t err_1 = flash_ctrl_data_erase(FLASH_CTRL_PARAM_BYTES_PER_BANK,
+__attribute__((warn_unused_result)) bool eflash_chip_erase(uintptr_t flash_ctrl_addr) {
+  flash_ctrl_bank_erase_perms_set(flash_ctrl_addr, kHardenedBoolTrue);
+  rom_error_t err_0 = flash_ctrl_data_erase(flash_ctrl_addr, 0, kFlashCtrlEraseTypeBank);
+  rom_error_t err_1 = flash_ctrl_data_erase(flash_ctrl_addr, FLASH_CTRL_PARAM_BYTES_PER_BANK,
                                             kFlashCtrlEraseTypeBank);
-  flash_ctrl_bank_erase_perms_set(kHardenedBoolFalse);
+  flash_ctrl_bank_erase_perms_set(flash_ctrl_addr, kHardenedBoolFalse);
   if (err_0 != kErrorOk || err_1 != kErrorOk) {
     return false;
   }
@@ -49,20 +49,21 @@
 // Writes 256-bytes from src to dst.
 // For now, lets take dst as a memory address, and mask off the top.
 #define EFLASH_PAGE_SIZE (256)
-__attribute__((warn_unused_result)) bool eflash_write_page(const void* dst,
+__attribute__((warn_unused_result)) bool eflash_write_page(uintptr_t flash_ctrl_addr,
+                                                           const void* dst,
                                                            uint8_t* src) {
   uint32_t flash_dst = (uint32_t)dst & ~TOP_MATCHA_EFLASH_BASE_ADDR;
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(flash_ctrl_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4False,
       .write = kMultiBitBool4True,
       .erase = kMultiBitBool4False,
   });
   rom_error_t err = flash_ctrl_data_write(
-      flash_dst, EFLASH_PAGE_SIZE / sizeof(uint32_t), src);
+      flash_ctrl_addr, flash_dst, EFLASH_PAGE_SIZE / sizeof(uint32_t), src);
   if (err != kErrorOk) {
     return false;
   }
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(flash_ctrl_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4True,
       .write = kMultiBitBool4False,
       .erase = kMultiBitBool4False,
@@ -335,7 +336,7 @@
   return sizeof(tar_header);
 }
 
-int load_bin_from_tar(const char* filename, uint8_t* base_addr) {
+int load_bin_from_tar(uintptr_t flash_ctrl_addr, const char* filename, uint8_t* base_addr) {
   size_t size = 0;
   size_t bin_offset = reinterpret_cast<size_t>(
       find_file_in_tar(filename, tar_read_data_from_spi, &size));
@@ -349,8 +350,8 @@
   while (remaining >= SPI_PAGE_SIZE) {
     size_t offset = size - remaining;
     spi_read_page(&spi_host0, bin_offset + offset, page);
-    result = eflash_write_page(base_addr + offset, page);
-    result = eflash_write_page(base_addr + offset + EFLASH_PAGE_SIZE,
+    result = eflash_write_page(flash_ctrl_addr, base_addr + offset, page);
+    result = eflash_write_page(flash_ctrl_addr, base_addr + offset + EFLASH_PAGE_SIZE,
                                page + EFLASH_PAGE_SIZE);
     remaining -= SPI_PAGE_SIZE;
   }
@@ -358,8 +359,8 @@
   if (remaining) {
     size_t offset = size - remaining;
     spi_read_page(&spi_host0, bin_offset + offset, page);
-    result = eflash_write_page(base_addr + offset, page);
-    result = eflash_write_page(base_addr + offset + EFLASH_PAGE_SIZE,
+    result = eflash_write_page(flash_ctrl_addr, base_addr + offset, page);
+    result = eflash_write_page(flash_ctrl_addr, base_addr + offset + EFLASH_PAGE_SIZE,
                                page + EFLASH_PAGE_SIZE);
   }
   return 1;
@@ -382,7 +383,8 @@
   flash_ctrl_testutils_wait_for_init(&flash_ctrl);
   dif_flash_ctrl_set_flash_enablement(&flash_ctrl, kDifToggleEnabled);
   dif_flash_ctrl_set_exec_enablement(&flash_ctrl, kDifToggleEnabled);
-  if (!eflash_chip_erase()) {
+  const uintptr_t flash_ctrl_addr = TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR;
+  if (!eflash_chip_erase(flash_ctrl_addr)) {
     io.printf("Erasing eflash failed\n");
     io.etx();
     return 0;
@@ -400,7 +402,7 @@
 
   // Find the tock binary in the external flash.
   const char* kScBinary = "matcha-tock-bundle.bin";
-  int ret = load_bin_from_tar(kScBinary, kEflashBase);
+  int ret = load_bin_from_tar(flash_ctrl_addr, kScBinary, kEflashBase);
 
   if (!ret) {
     io.printf("Didn't find %s, don't try to start.\n", kScBinary);
diff --git a/sw/device/lib/testing/test_rom/test_rom.c b/sw/device/lib/testing/test_rom/test_rom.c
index d95b6a5..c277750 100644
--- a/sw/device/lib/testing/test_rom/test_rom.c
+++ b/sw/device/lib/testing/test_rom/test_rom.c
@@ -86,13 +86,15 @@
 // rom tests. By default, it simply jumps into the OTTF's flash.
 OT_WEAK
 bool rom_test_main(void) {
+  const uintptr_t otp_addr = TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR;
+
   // Check the otp to see if execute should start
   // val: 0xFFFFFFFF
 #if defined(OTP_IS_RAM)
   uint32_t otp_val = 0xffffffff;
 #else
-  uint32_t otp_val = abs_mmio_read32(
-      TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR + OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
+  uint32_t otp_val = abs_mmio_read32(otp_addr +
+      OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
       OTP_CTRL_PARAM_CREATOR_SW_CFG_ROM_EXEC_EN_OFFSET);
 #endif
 
@@ -109,8 +111,8 @@
 #if defined(OTP_IS_RAM)
   uint32_t cpuctrl_otp_val = 0x1;
 #else
-  uint32_t cpuctrl_otp_val = abs_mmio_read32(
-      TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR + OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
+  uint32_t cpuctrl_otp_val = abs_mmio_read32(otp_addr +
+      OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
       OTP_CTRL_PARAM_CREATOR_SW_CFG_CPUCTRL_OFFSET);
 #endif
   cpuctrl_csr = bitfield_field32_write(
@@ -217,18 +219,15 @@
     CHECK_DIF_OK(dif_flash_ctrl_set_default_region_properties(
         &flash_ctrl, default_properties));
   }
-  const mmio_region_t otp_addr =
-      mmio_region_from_addr(TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR);
-  const mmio_region_t gpio_addr =
-      mmio_region_from_addr(TOP_MATCHA_GPIO_BASE_ADDR);
+  const uintptr_t gpio_addr = TOP_MATCHA_GPIO_BASE_ADDR;
   if (bootstrap_requested(otp_addr, gpio_addr) == kHardenedBoolTrue) {
     // This log statement is used to synchronize the rom and DV testbench
     // for specific test cases.
     LOG_INFO("Boot strap requested");
 
-    const mmio_region_t spi_device_addr =
-        mmio_region_from_addr(TOP_MATCHA_SPI_DEVICE_BASE_ADDR);
-    rom_error_t bootstrap_err = bootstrap(otp_addr, gpio_addr, spi_device_addr);
+    const uintptr_t flash_ctrl_addr = TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR;
+    const uintptr_t spi_device_addr = TOP_MATCHA_SPI_DEVICE_BASE_ADDR;
+    rom_error_t bootstrap_err = bootstrap(flash_ctrl_addr, spi_device_addr, otp_addr, gpio_addr);
     if (bootstrap_err != kErrorOk) {
       LOG_ERROR("Bootstrap failed with status code: %08x",
                 (uint32_t)bootstrap_err);
@@ -247,11 +246,9 @@
       entry_point >
           TOP_MATCHA_EFLASH_BASE_ADDR + TOP_MATCHA_EFLASH_SIZE_BYTES) {
     LOG_INFO("Attempting to load from external flash...");
-    const mmio_region_t spi_host_addr =
-        mmio_region_from_addr(TOP_MATCHA_SPI_HOST0_BASE_ADDR);
-    const mmio_region_t eflash_addr =
-        mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR);
-    spi_flash_init(spi_host_addr, eflash_addr, otp_addr);
+    const uintptr_t spi_host_addr = TOP_MATCHA_SPI_HOST0_BASE_ADDR;
+    const uintptr_t flash_ctrl_addr = TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR;
+    spi_flash_init(spi_host_addr, flash_ctrl_addr, otp_addr);
     dif_result_t load_result = load_file_from_tar(
         "matcha-tock-bundle.bin", (void *)TOP_MATCHA_EFLASH_BASE_ADDR,
         TOP_MATCHA_EFLASH_BASE_ADDR + TOP_MATCHA_EFLASH_SIZE_BYTES);
diff --git a/sw/device/lib/testing/test_rom/test_rom_cheri.c b/sw/device/lib/testing/test_rom/test_rom_cheri.c
index fe7e7bc..5040f97 100644
--- a/sw/device/lib/testing/test_rom/test_rom_cheri.c
+++ b/sw/device/lib/testing/test_rom/test_rom_cheri.c
@@ -71,12 +71,19 @@
 static dif_uart_t uart0;
 static dif_rv_core_ibex_t ibex;
 
-// Helper to craft an mmio_region_t for fixed address.
+// Helper to craft a uintptr_t for a fixed address.
+static inline uintptr_t get_mmio_ptr(const uintptr_t root_cap,
+                                     const uint32_t base_addr,
+                                     const uint32_t size_bytes) {
+  return cderivecap(root_cap, base_addr, size_bytes,
+                    CHERI_PERM_LOAD | CHERI_PERM_STORE);
+}
+
+// Helper to craft an mmio_region_t for a fixed address.
 static inline mmio_region_t get_mmio_region(const uintptr_t root_cap,
                                             const uint32_t base_addr,
                                             const uint32_t size_bytes) {
-  return mmio_region_from_addr(cderivecap(root_cap, base_addr, size_bytes,
-                                          CHERI_PERM_LOAD | CHERI_PERM_STORE));
+  return mmio_region_from_addr(get_mmio_ptr(root_cap, base_addr, size_bytes));
 }
 
 // Helper to read a 32-bit value from a fixed address.
@@ -90,13 +97,16 @@
 // rom tests. By default, it simply jumps into the OTTF's flash.
 OT_WEAK
 bool rom_test_main(const uintptr_t root_cap) {
+  const uintptr_t otp_addr =
+      get_mmio_ptr(root_cap, TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR,
+                   TOP_MATCHA_OTP_CTRL_CORE_SIZE_BYTES);
+
   // Check the otp to see if execute should start
   // val: 0xFFFFFFFF
 #if defined(OTP_IS_RAM)
   uint32_t otp_val = 0xffffffff;
 #else
-  uint32_t otp_val = mmio_read32(
-      root_cap, TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR +
+  uint32_t otp_val = abs_mmio_read32(otp_addr +
                     OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
                     OTP_CTRL_PARAM_CREATOR_SW_CFG_ROM_EXEC_EN_OFFSET);
 #endif
@@ -115,9 +125,9 @@
   uint32_t cpuctrl_otp_val = 0x1;
 #else
   uint32_t cpuctrl_otp_val =
-      mmio_read32(root_cap, TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR +
-                                OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
-                                OTP_CTRL_PARAM_CREATOR_SW_CFG_CPUCTRL_OFFSET);
+      abs_mmio_read32(otp_addr +
+                      OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
+                      OTP_CTRL_PARAM_CREATOR_SW_CFG_CPUCTRL_OFFSET);
 #endif
   cpuctrl_csr = bitfield_field32_write(
       cpuctrl_csr, (bitfield_field32_t){.mask = 0x3f, .index = 0},
@@ -217,9 +227,8 @@
 #if defined(OTP_IS_RAM)
   otp_val = 0;
 #else
-  otp_val = mmio_read32(
-      root_cap,
-      TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR + OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
+  otp_val = abs_mmio_read32(otp_addr +
+          OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
           OTP_CTRL_PARAM_CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG_OFFSET);
 #endif
 
@@ -237,20 +246,22 @@
         &flash_ctrl, default_properties));
   }
   // TODO(sleffler): cannot run from eFLASH so this is pointless
-  const mmio_region_t otp_addr =
-      get_mmio_region(root_cap, TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR,
-                      TOP_MATCHA_OTP_CTRL_CORE_SIZE_BYTES);
-  const mmio_region_t gpio_addr = get_mmio_region(
-      root_cap, TOP_MATCHA_GPIO_BASE_ADDR, TOP_MATCHA_GPIO_SIZE_BYTES);
+  const uintptr_t gpio_addr =
+      get_mmio_ptr(root_cap, TOP_MATCHA_GPIO_BASE_ADDR,
+                   TOP_MATCHA_GPIO_SIZE_BYTES);
   if (bootstrap_requested(otp_addr, gpio_addr) == kHardenedBoolTrue) {
     // This log statement is used to synchronize the rom and DV testbench
     // for specific test cases.
     LOG_INFO("Boot strap requested");
 
-    const mmio_region_t spi_device_addr =
-        get_mmio_region(root_cap, TOP_MATCHA_SPI_DEVICE_BASE_ADDR,
-                        TOP_MATCHA_SPI_DEVICE_BASE_ADDR);
-    rom_error_t bootstrap_err = bootstrap(otp_addr, gpio_addr, spi_device_addr);
+    const uintptr_t flash_ctrl_addr =
+        get_mmio_ptr(root_cap, TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR,
+                     TOP_MATCHA_FLASH_CTRL_CORE_SIZE_BYTES);
+    const uintptr_t spi_device_addr =
+        get_mmio_ptr(root_cap, TOP_MATCHA_SPI_DEVICE_BASE_ADDR,
+                     TOP_MATCHA_SPI_DEVICE_BASE_ADDR);
+    rom_error_t bootstrap_err = bootstrap(flash_ctrl_addr, spi_device_addr,
+                                          otp_addr, gpio_addr);
     if (bootstrap_err != kErrorOk) {
       LOG_ERROR("Bootstrap failed with status code: %08x",
                 (uint32_t)bootstrap_err);
@@ -272,22 +283,21 @@
       entry_point >
           TOP_MATCHA_EFLASH_BASE_ADDR + TOP_MATCHA_EFLASH_SIZE_BYTES) {
     LOG_INFO("Attempting to load from external flash...");
-    const mmio_region_t spi_host_addr =
-        get_mmio_region(root_cap, TOP_MATCHA_SPI_HOST0_BASE_ADDR,
-                        TOP_MATCHA_SPI_HOST0_SIZE_BYTES);
-    const mmio_region_t eflash_addr =
-        get_mmio_region(root_cap, TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR,
-                        TOP_MATCHA_FLASH_CTRL_CORE_SIZE_BYTES);
-    spi_flash_init(spi_host_addr, eflash_addr, otp_addr);
+    const uintptr_t spi_host_addr =
+        get_mmio_ptr(root_cap, TOP_MATCHA_SPI_HOST0_BASE_ADDR,
+                     TOP_MATCHA_SPI_HOST0_SIZE_BYTES);
+    const uintptr_t flash_ctrl_addr =
+        get_mmio_ptr(root_cap, TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR,
+                     TOP_MATCHA_FLASH_CTRL_CORE_SIZE_BYTES);
+    spi_flash_init(spi_host_addr, flash_ctrl_addr, otp_addr);
     // XXX max_mem_addr should not include the stack
 #if 0
     // NB: cannot run from eFLASH because global caps cannot be represented
     //   without tagged memory; this is left here in case something changes.
     dif_result_t load_result = load_file_from_tar(
         CHERIOT_FIRMWARE,
-        (void*) cderivecap(root_cap,
-            TOP_MATCHA_EFLASH_BASE_ADDR, TOP_MATCHA_EFLASH_SIZE_BYTES,
-            CHERI_PERM_LOAD | CHERI_PERM_STORE),
+        (void*) get_mmio_ptr(root_cap,
+            TOP_MATCHA_EFLASH_BASE_ADDR, TOP_MATCHA_EFLASH_SIZE_BYTES),
         TOP_MATCHA_EFLASH_BASE_ADDR + TOP_MATCHA_EFLASH_SIZE_BYTES);
     if (load_result == kDifOk) {
       entry_point = manifest_entry_point_get(manifest);
@@ -295,9 +305,8 @@
     // Load from SPI to RAM.
     dif_result_t load_result = load_file_from_tar(
         CHERIOT_FIRMWARE,
-        // TODO(sleffler): get memory configuration from SOT
-        (void *)cderivecap(root_cap, RAM_START, RAM_SIZE_BYTES,
-                           CHERI_PERM_LOAD | CHERI_PERM_STORE),
+        // TODO(sleffler): get RAM configuration from SOT
+        (void *)get_mmio_ptr(root_cap, RAM_START, RAM_SIZE_BYTES),
         RAM_START + RAM_SIZE_BYTES);
     if (load_result == kDifOk) {
       // TODO(sleffler): get entry point from manifest
diff --git a/sw/device/silicon_creator/rom/bootstrap.c b/sw/device/silicon_creator/rom/bootstrap.c
index f31b154..bfccc7c 100644
--- a/sw/device/silicon_creator/rom/bootstrap.c
+++ b/sw/device/silicon_creator/rom/bootstrap.c
@@ -83,12 +83,12 @@
  *
  * @return Result of the operation.
  */
-static rom_error_t bootstrap_chip_erase(void) {
-  flash_ctrl_bank_erase_perms_set(kHardenedBoolTrue);
-  rom_error_t err_0 = flash_ctrl_data_erase(0, kFlashCtrlEraseTypeBank);
-  rom_error_t err_1 = flash_ctrl_data_erase(FLASH_CTRL_PARAM_BYTES_PER_BANK,
+static rom_error_t bootstrap_chip_erase(uintptr_t flash_ctrl_addr) {
+  flash_ctrl_bank_erase_perms_set(flash_ctrl_addr, kHardenedBoolTrue);
+  rom_error_t err_0 = flash_ctrl_data_erase(flash_ctrl_addr, 0, kFlashCtrlEraseTypeBank);
+  rom_error_t err_1 = flash_ctrl_data_erase(flash_ctrl_addr, FLASH_CTRL_PARAM_BYTES_PER_BANK,
                                             kFlashCtrlEraseTypeBank);
-  flash_ctrl_bank_erase_perms_set(kHardenedBoolFalse);
+  flash_ctrl_bank_erase_perms_set(flash_ctrl_addr, kHardenedBoolFalse);
 
   HARDENED_RETURN_IF_ERROR(err_0);
   return err_1;
@@ -104,7 +104,7 @@
  * @param addr Address that falls within the 4 KiB region being deleted.
  * @return Result of the operation.
  */
-static rom_error_t bootstrap_sector_erase(uint32_t addr) {
+static rom_error_t bootstrap_sector_erase(uintptr_t flash_ctrl_addr, uint32_t addr) {
   static_assert(FLASH_CTRL_PARAM_BYTES_PER_PAGE == 2048,
                 "Page size must be 2 KiB");
   enum {
@@ -119,15 +119,15 @@
   }
   addr &= kPageAddrMask;
 
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(flash_ctrl_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4False,
       .write = kMultiBitBool4False,
       .erase = kMultiBitBool4True,
   });
-  rom_error_t err_0 = flash_ctrl_data_erase(addr, kFlashCtrlEraseTypePage);
-  rom_error_t err_1 = flash_ctrl_data_erase(
+  rom_error_t err_0 = flash_ctrl_data_erase(flash_ctrl_addr, addr, kFlashCtrlEraseTypePage);
+  rom_error_t err_1 = flash_ctrl_data_erase(flash_ctrl_addr,
       addr + FLASH_CTRL_PARAM_BYTES_PER_PAGE, kFlashCtrlEraseTypePage);
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(flash_ctrl_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4False,
       .write = kMultiBitBool4False,
       .erase = kMultiBitBool4False,
@@ -152,7 +152,8 @@
  * flash word.
  * @return Result of the operation.
  */
-static rom_error_t bootstrap_page_program(uint32_t addr, size_t byte_count,
+static rom_error_t bootstrap_page_program(uintptr_t flash_ctrl_addr,
+                                          uint32_t addr, size_t byte_count,
                                           uint8_t *data) {
   static_assert(__builtin_popcount(FLASH_CTRL_PARAM_BYTES_PER_WORD) == 1,
                 "Bytes per flash word must be a power of two.");
@@ -189,7 +190,7 @@
   }
   size_t rem_word_count = byte_count / sizeof(uint32_t);
 
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(flash_ctrl_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4False,
       .write = kMultiBitBool4True,
       .erase = kMultiBitBool4False,
@@ -204,7 +205,7 @@
     if (word_count > rem_word_count) {
       word_count = rem_word_count;
     }
-    err_0 = flash_ctrl_data_write(addr, word_count, data);
+    err_0 = flash_ctrl_data_write(flash_ctrl_addr, addr, word_count, data);
     rem_word_count -= word_count;
     data += word_count * sizeof(uint32_t);
     // Wrap to the beginning of the current page since PAGE_PROGRAM modifies
@@ -213,9 +214,9 @@
   }
   rom_error_t err_1 = kErrorOk;
   if (rem_word_count > 0) {
-    err_1 = flash_ctrl_data_write(addr, rem_word_count, data);
+    err_1 = flash_ctrl_data_write(flash_ctrl_addr, addr, rem_word_count, data);
   }
-  flash_ctrl_data_default_perms_set((flash_ctrl_perms_t){
+  flash_ctrl_data_default_perms_set(flash_ctrl_addr, (flash_ctrl_perms_t){
       .read = kMultiBitBool4False,
       .write = kMultiBitBool4False,
       .erase = kMultiBitBool4False,
@@ -235,13 +236,13 @@
  * @param state Bootstrap state.
  * @return Result of the operation.
  */
-static rom_error_t bootstrap_handle_erase(bootstrap_state_t *state) {
+static rom_error_t bootstrap_handle_erase(uintptr_t flash_ctrl_addr, uintptr_t spi_device_addr, bootstrap_state_t *state) {
   HARDENED_CHECK_EQ(*state, kBootstrapStateErase);
 
   spi_device_cmd_t cmd;
-  RETURN_IF_ERROR(spi_device_cmd_get(&cmd));
+  RETURN_IF_ERROR(spi_device_cmd_get(spi_device_addr, &cmd));
   // Erase requires WREN, ignore if WEL is not set.
-  if (!bitfield_bit32_read(spi_device_flash_status_get(), kSpiDeviceWelBit)) {
+  if (!bitfield_bit32_read(spi_device_flash_status_get(spi_device_addr), kSpiDeviceWelBit)) {
     return kErrorOk;
   }
 
@@ -249,7 +250,7 @@
   switch (cmd.opcode) {
     case kSpiDeviceOpcodeChipErase:
     case kSpiDeviceOpcodeSectorErase:
-      error = bootstrap_chip_erase();
+      error = bootstrap_chip_erase(flash_ctrl_addr);
       HARDENED_RETURN_IF_ERROR(error);
       *state = kBootstrapStateEraseVerify;
       // Note: We clear WIP and WEN bits in `bootstrap_handle_erase_verify()`
@@ -258,7 +259,7 @@
     default:
       // Ignore any other command, e.g. PAGE_PROGRAM, RESET, and clear WIP and
       // WEN bits right away.
-      spi_device_flash_status_clear();
+      spi_device_flash_status_clear(spi_device_addr);
       error = kErrorOk;
   }
 
@@ -273,17 +274,17 @@
  * @param state Bootstrap state.
  * @return Result of the operation.
  */
-static rom_error_t bootstrap_handle_erase_verify(bootstrap_state_t *state) {
+static rom_error_t bootstrap_handle_erase_verify(uintptr_t flash_ctrl_addr, uintptr_t spi_device_addr, bootstrap_state_t *state) {
   HARDENED_CHECK_EQ(*state, kBootstrapStateEraseVerify);
 
-  rom_error_t err_0 = flash_ctrl_data_erase_verify(0, kFlashCtrlEraseTypeBank);
-  rom_error_t err_1 = flash_ctrl_data_erase_verify(
+  rom_error_t err_0 = flash_ctrl_data_erase_verify(flash_ctrl_addr, 0, kFlashCtrlEraseTypeBank);
+  rom_error_t err_1 = flash_ctrl_data_erase_verify(flash_ctrl_addr,
       FLASH_CTRL_PARAM_BYTES_PER_BANK, kFlashCtrlEraseTypeBank);
   HARDENED_RETURN_IF_ERROR(err_0);
   HARDENED_RETURN_IF_ERROR(err_1);
 
   *state = kBootstrapStateProgram;
-  spi_device_flash_status_clear();
+  spi_device_flash_status_clear(spi_device_addr);
   return err_0;
 }
 
@@ -293,7 +294,7 @@
  * @param state Bootstrap state.
  * @return Result of the operation.
  */
-static rom_error_t bootstrap_handle_program(bootstrap_state_t *state) {
+static rom_error_t bootstrap_handle_program(uintptr_t flash_ctrl_addr, uintptr_t spi_device_addr, bootstrap_state_t *state) {
   static_assert(alignof(spi_device_cmd_t) >= sizeof(uint32_t) &&
                     offsetof(spi_device_cmd_t, payload) >= sizeof(uint32_t),
                 "Payload must be word aligned.");
@@ -305,23 +306,23 @@
   HARDENED_CHECK_EQ(*state, kBootstrapStateProgram);
 
   spi_device_cmd_t cmd;
-  RETURN_IF_ERROR(spi_device_cmd_get(&cmd));
+  RETURN_IF_ERROR(spi_device_cmd_get(spi_device_addr, &cmd));
   // Erase and program require WREN, ignore if WEL is not set.
   if (cmd.opcode != kSpiDeviceOpcodeReset &&
-      !bitfield_bit32_read(spi_device_flash_status_get(), kSpiDeviceWelBit)) {
+      !bitfield_bit32_read(spi_device_flash_status_get(spi_device_addr), kSpiDeviceWelBit)) {
     return kErrorOk;
   }
 
   rom_error_t error = kErrorUnknown;
   switch (cmd.opcode) {
     case kSpiDeviceOpcodeChipErase:
-      error = bootstrap_chip_erase();
+      error = bootstrap_chip_erase(flash_ctrl_addr);
       break;
     case kSpiDeviceOpcodeSectorErase:
-      error = bootstrap_sector_erase(cmd.address);
+      error = bootstrap_sector_erase(flash_ctrl_addr, cmd.address);
       break;
     case kSpiDeviceOpcodePageProgram:
-      error = bootstrap_page_program(cmd.address, cmd.payload_byte_count,
+      error = bootstrap_page_program(flash_ctrl_addr, cmd.address, cmd.payload_byte_count,
                                      cmd.payload);
       break;
     case kSpiDeviceOpcodeReset:
@@ -342,12 +343,11 @@
   }
   HARDENED_RETURN_IF_ERROR(error);
 
-  spi_device_flash_status_clear();
+  spi_device_flash_status_clear(spi_device_addr);
   return error;
 }
 
-hardened_bool_t bootstrap_requested(mmio_region_t otp_addr,
-                                    mmio_region_t gpio_addr) {
+hardened_bool_t bootstrap_requested(uintptr_t otp_addr, uintptr_t gpio_addr) {
 #if defined(OTP_IS_RAM)
   uint32_t res = kHardenedBoolTrue;
 #else
@@ -362,7 +362,9 @@
   // A single read is sufficient since we expect strong pull-ups on the strap
   // pins.
   res ^= SW_STRAP_BOOTSTRAP;
-  res ^= mmio_region_read32(gpio_addr, GPIO_DATA_IN_REG_OFFSET) & SW_STRAP_MASK;
+  res ^=
+      abs_mmio_read32(gpio_addr + GPIO_DATA_IN_REG_OFFSET) &
+      SW_STRAP_MASK;
   if (launder32(res) != kHardenedBoolTrue) {
     return kHardenedBoolFalse;
   }
@@ -371,8 +373,10 @@
 }
 
 // NB: assumes flash_ctrl_init is already called
-rom_error_t bootstrap(mmio_region_t otp_addr, mmio_region_t gpio_addr,
-                      mmio_region_t spi_device_addr) {
+rom_error_t bootstrap(uintptr_t flash_ctrl_addr,
+                      uintptr_t spi_device_addr,
+                      uintptr_t otp_addr,
+                      uintptr_t gpio_addr) {
   hardened_bool_t requested = bootstrap_requested(otp_addr, gpio_addr);
   if (launder32(requested) != kHardenedBoolTrue) {
     return kErrorBootstrapNotRequested;
@@ -388,15 +392,15 @@
     switch (launder32(state)) {
       case kBootstrapStateErase:
         HARDENED_CHECK_EQ(state, kBootstrapStateErase);
-        error = bootstrap_handle_erase(&state);
+        error = bootstrap_handle_erase(flash_ctrl_addr, spi_device_addr, &state);
         break;
       case kBootstrapStateEraseVerify:
         HARDENED_CHECK_EQ(state, kBootstrapStateEraseVerify);
-        error = bootstrap_handle_erase_verify(&state);
+        error = bootstrap_handle_erase_verify(flash_ctrl_addr, spi_device_addr, &state);
         break;
       case kBootstrapStateProgram:
         HARDENED_CHECK_EQ(state, kBootstrapStateProgram);
-        error = bootstrap_handle_program(&state);
+        error = bootstrap_handle_program(flash_ctrl_addr, spi_device_addr, &state);
         break;
       default:
         error = kErrorBootstrapInvalidState;
diff --git a/sw/device/silicon_creator/rom/bootstrap.h b/sw/device/silicon_creator/rom/bootstrap.h
index 758ae0b..c67b88e 100644
--- a/sw/device/silicon_creator/rom/bootstrap.h
+++ b/sw/device/silicon_creator/rom/bootstrap.h
@@ -35,8 +35,7 @@
  *
  * @return Whether bootstrap is requested.
  */
-hardened_bool_t bootstrap_requested(mmio_region_t otp_addr,
-                                    mmio_region_t gpio_addr);
+hardened_bool_t bootstrap_requested(uintptr_t otp_addr, uintptr_t gpio_addr);
 
 /**
  * Bootstraps the data partition of the embedded flash with data received by the
@@ -54,8 +53,10 @@
  *
  * @return Result of the operation.
  */
-rom_error_t bootstrap(mmio_region_t otp_addr, mmio_region_t gpio_addr,
-                      mmio_region_t spi_device_addr);
+rom_error_t bootstrap(uintptr_t flash_ctrl_addr,
+                      uintptr_t spi_device_addr,
+                      uintptr_t otp_addr,
+                      uintptr_t gpio_addr);
 
 #ifdef __cplusplus
 }
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c
index 9a77e38..2fdec4a 100644
--- a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c
+++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c
@@ -61,13 +61,10 @@
   test_status_set(kTestStatusInTest);
   init_uart(TOP_MATCHA_UART0_BASE_ADDR, &uart);
   LOG_INFO("kelvin_test_sc");
-  const mmio_region_t spi_host_addr =
-      mmio_region_from_addr(TOP_MATCHA_SPI_HOST0_BASE_ADDR);
-  const mmio_region_t eflash_addr =
-      mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR);
-  const mmio_region_t otp_addr =
-      mmio_region_from_addr(TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR);
-  spi_flash_init(spi_host_addr, eflash_addr, otp_addr);
+  const uintptr_t spi_host_addr = TOP_MATCHA_SPI_HOST0_BASE_ADDR;
+  const uintptr_t flash_ctrl_addr = TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR;
+  const uintptr_t otp_addr = TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR;
+  spi_flash_init(spi_host_addr, flash_ctrl_addr, otp_addr);
 
   // Copy binary to SMC RAM.
   CHECK_DIF_OK(load_file_from_tar(