[sw/silicon_creator] Allocate .static_critical section in memory

The .static_critical section is located at a fixed address
(currently the base address of main RAM). It will be used to
communicate critical information from one boot stage to the next.

Currently the only variable the section contains is sec_mmio_ctx.

Signed-off-by: Michael Munday <mike.munday@lowrisc.org>
diff --git a/sw/device/silicon_creator/lib/base/sec_mmio.c b/sw/device/silicon_creator/lib/base/sec_mmio.c
index 0267bc8..486d42d 100644
--- a/sw/device/silicon_creator/lib/base/sec_mmio.c
+++ b/sw/device/silicon_creator/lib/base/sec_mmio.c
@@ -7,8 +7,9 @@
 #include "sw/device/lib/base/memory.h"
 #include "sw/device/silicon_creator/lib/base/abs_mmio.h"
 
-// FIXME: Linker configuration.
-extern sec_mmio_ctx_t sec_mmio_ctx;
+// The context is declared as weak so that the mask ROM and ROM_EXT may
+// override its location.
+__attribute__((weak)) volatile sec_mmio_ctx_t sec_mmio_ctx;
 
 // FIXME: Replace for shutdown module handler.
 static sec_mmio_shutdown_handler sec_mmio_shutdown_cb;
diff --git a/sw/device/silicon_creator/lib/base/sec_mmio.h b/sw/device/silicon_creator/lib/base/sec_mmio.h
index af80850..18d648d 100644
--- a/sw/device/silicon_creator/lib/base/sec_mmio.h
+++ b/sw/device/silicon_creator/lib/base/sec_mmio.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "sw/device/lib/base/macros.h"
 #include "sw/device/silicon_creator/lib/error.h"
 
 #ifdef __cplusplus
@@ -47,9 +48,6 @@
  *
  * Opens:
  *
- * - sec_mmio_ctx is currently defined as an extern to simplify testing. For the
- *   actual target, we need to define a memory region to share the data with the
- *   ROM_EXT.
  * - Currently fault detection escalations are performed by calling a handler
  *   that is registered at `sec_mmio_init()` call time. Need to determine if we
  *   want to move to a mock_shutdown implementation, or if we want to refactor
@@ -106,6 +104,19 @@
 } sec_mmio_ctx_t;
 
 /**
+ * The `sec_mmio_ctx_t` structure is accessible by both the mask ROM and ROM
+ * extension. It's layout is therefore fixed and any changes must be applied
+ * to both boot stages.
+ */
+OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, values, 0);
+OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, addrs, 400);
+OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, last_index, 800);
+OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, write_count, 804);
+OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, expected_write_count, 808);
+OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, check_count, 812);
+OT_ASSERT_SIZE(sec_mmio_ctx_t, 816);  // Checked by linker script.
+
+/**
  * Shutdown module callback handler.
  */
 typedef void (*sec_mmio_shutdown_handler)(rom_error_t);
diff --git a/sw/device/silicon_creator/lib/base/sec_mmio_unittest.cc b/sw/device/silicon_creator/lib/base/sec_mmio_unittest.cc
index e728b98..8cdfb71 100644
--- a/sw/device/silicon_creator/lib/base/sec_mmio_unittest.cc
+++ b/sw/device/silicon_creator/lib/base/sec_mmio_unittest.cc
@@ -13,8 +13,8 @@
 #include "sw/device/silicon_creator/lib/error.h"
 
 extern "C" {
-// This is an extern in the sec_mmio module.
-sec_mmio_ctx_t sec_mmio_ctx;
+// Declared in the sec_mmio module.
+extern sec_mmio_ctx_t sec_mmio_ctx;
 }
 
 namespace sec_mmio_unittest {
diff --git a/sw/device/silicon_creator/lib/base/static_critical.ld b/sw/device/silicon_creator/lib/base/static_critical.ld
new file mode 100644
index 0000000..03e7dc3
--- /dev/null
+++ b/sw/device/silicon_creator/lib/base/static_critical.ld
@@ -0,0 +1,14 @@
+/* Copyright lowRISC contributors. */
+/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/**
+ * Variables stored in the .static_critical section of RAM.
+ *
+ * This should be included into a NOLOAD .static_critical section located at
+ * the origin of main RAM.
+ */
+ASSERT(. == ORIGIN(ram_main), "Error: .static_critical section not at the base address of main RAM.");
+ASSERT(. - ADDR(.static_critical) == 0, "Error: .static_critical.sec_mmio_ctx section offset has changed.");
+KEEP(*(.static_critical.sec_mmio_ctx))
+ASSERT(. - ADDR(.static_critical) == 816, "Error: .static_critical.sec_mmio_ctx section size has changed");
diff --git a/sw/device/silicon_creator/lib/drivers/alert_functest.c b/sw/device/silicon_creator/lib/drivers/alert_functest.c
index b90dba1..de8c9a1 100644
--- a/sw/device/silicon_creator/lib/drivers/alert_functest.c
+++ b/sw/device/silicon_creator/lib/drivers/alert_functest.c
@@ -31,9 +31,6 @@
   kFlashBase = TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR,
 };
 
-// sec_mmio (used by the alert driver) requires this symbol to be defined.
-sec_mmio_ctx_t sec_mmio_ctx;
-
 rom_error_t alert_no_escalate_test(void) {
   // Configure class B alerts for phase 0 only and disable NMI signalling.
   alert_class_config_t config = {
diff --git a/sw/device/silicon_creator/lib/drivers/keymgr_functest.c b/sw/device/silicon_creator/lib/drivers/keymgr_functest.c
index acb782c..49355f9 100644
--- a/sw/device/silicon_creator/lib/drivers/keymgr_functest.c
+++ b/sw/device/silicon_creator/lib/drivers/keymgr_functest.c
@@ -37,9 +37,6 @@
 
 #define ASSERT_EQZ(x) CHECK((x) == 0)
 
-// sec_mmio (used by the lifecycle driver) requires this symbol to be defined.
-sec_mmio_ctx_t sec_mmio_ctx;
-
 enum {
   /** Creator Secret flash info page ID. */
   kFlashInfoPageIdCreatorSecret = 1,
diff --git a/sw/device/silicon_creator/lib/sigverify_functest.c b/sw/device/silicon_creator/lib/sigverify_functest.c
index 312dd2b..f8355fe 100644
--- a/sw/device/silicon_creator/lib/sigverify_functest.c
+++ b/sw/device/silicon_creator/lib/sigverify_functest.c
@@ -12,9 +12,6 @@
 // Digest of the test message above.
 hmac_digest_t act_digest;
 
-// sec_mmio (used by the OTP driver) requires this symbol to be defined.
-sec_mmio_ctx_t sec_mmio_ctx;
-
 // See sw/device/silicon_creator/keys/README.md for more details on how to
 // update the structs below.
 
diff --git a/sw/device/silicon_creator/mask_rom/mask_rom.c b/sw/device/silicon_creator/mask_rom/mask_rom.c
index 0e60ea4..dd1c10c 100644
--- a/sw/device/silicon_creator/mask_rom/mask_rom.c
+++ b/sw/device/silicon_creator/mask_rom/mask_rom.c
@@ -30,10 +30,13 @@
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
 
-// TODO(#7325): Defined here for now to be able to use the OTP driver since
-// 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;
+// Secure MMIO context.
+//
+// This is placed at a fixed location in memory within the .static_critical
+// section. The location of this data is known to ROM_EXT.
+__attribute__((section(".static_critical.sec_mmio_ctx")))  //
+volatile 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.
diff --git a/sw/device/silicon_creator/mask_rom/mask_rom.ld b/sw/device/silicon_creator/mask_rom/mask_rom.ld
index ca98193..4784c6e 100644
--- a/sw/device/silicon_creator/mask_rom/mask_rom.ld
+++ b/sw/device/silicon_creator/mask_rom/mask_rom.ld
@@ -105,13 +105,27 @@
   } > rom
 
   /**
-   * Mutable data section, at the bottom of ram_main. This will be initialized
-   * from rom at runtime by the CRT.
+   * Critical static data that is accessible by both the mask ROM and the ROM
+   * extension.
    *
-   * Load this by copying the bytes from [_data_init_start, _data_init_end] into
-   * the range [_data_start, _data_end].
+   * Each variable added to .static_critical must be in its own subsection
+   * named after the variable.
+   *
+   * This data is not initialized during CRT (hence NOLOAD). The mask ROM must
+   * initialize this data explicitly.
    */
-  .data ORIGIN(ram_main) : ALIGN(4) {
+  .static_critical ORIGIN(ram_main) (NOLOAD) : ALIGN(4) {
+    INCLUDE sw/device/silicon_creator/lib/base/static_critical.ld
+  } > ram_main
+
+  /**
+   * Mutable data section. This will be initialized from rom at runtime by the
+   * CRT.
+   *
+   * Load this by copying the bytes from [_data_init_start, _data_init_end) into
+   * the range [_data_start, _data_end).
+   */
+  .data : ALIGN(4) {
     _data_start = .;
     _data_init_start = LOADADDR(.data);
 
diff --git a/sw/device/silicon_creator/mask_rom/mask_rom_epmp_test.c b/sw/device/silicon_creator/mask_rom/mask_rom_epmp_test.c
index 46c358c..69e1429 100644
--- a/sw/device/silicon_creator/mask_rom/mask_rom_epmp_test.c
+++ b/sw/device/silicon_creator/mask_rom/mask_rom_epmp_test.c
@@ -17,6 +17,7 @@
 #include "sw/device/lib/runtime/print.h"
 #include "sw/device/lib/testing/test_framework/test_status.h"
 #include "sw/device/silicon_creator/lib/base/abs_mmio.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
 #include "sw/device/silicon_creator/lib/drivers/uart.h"
 #include "sw/device/silicon_creator/lib/epmp_test_unlock.h"
 #include "sw/device/silicon_creator/mask_rom/mask_rom_epmp.h"
@@ -35,6 +36,15 @@
  */
 
 /**
+ * Secure MMIO context.
+ *
+ * This is placed at a fixed location in memory within the .static_critical
+ * section. The location of this data is known to ROM_EXT.
+ */
+__attribute__((section(".static_critical.sec_mmio_ctx")))  //
+volatile sec_mmio_ctx_t sec_mmio_ctx;
+
+/**
  * Exception types that may be encountered.
  *
  * TODO(#7190): use global definitions instead.
diff --git a/sw/device/silicon_creator/mask_rom/meson.build b/sw/device/silicon_creator/mask_rom/meson.build
index 2499f34..f05c6ed 100644
--- a/sw/device/silicon_creator/mask_rom/meson.build
+++ b/sw/device/silicon_creator/mask_rom/meson.build
@@ -68,6 +68,7 @@
   link_args: rom_link_args,
   dependencies: [
     freestanding_headers,
+    sw_silicon_creator_lib_base_sec_mmio,
     sw_silicon_creator_lib_driver_uart,
     sw_silicon_creator_lib_epmp_test_unlock,
     sw_silicon_creator_lib_fake_deps,
diff --git a/sw/device/silicon_creator/rom_exts/meson.build b/sw/device/silicon_creator/rom_exts/meson.build
index 28806bf..ccaaffa 100644
--- a/sw/device/silicon_creator/rom_exts/meson.build
+++ b/sw/device/silicon_creator/rom_exts/meson.build
@@ -51,6 +51,7 @@
         sw_lib_dif_uart,
         sw_lib_runtime_hart,
         sw_lib_runtime_print,
+        sw_silicon_creator_lib_base_sec_mmio,
         sw_silicon_creator_lib_manifest_section,
 
         # TODO: ePMP test status dependency should be removed from
diff --git a/sw/device/silicon_creator/rom_exts/rom_ext.c b/sw/device/silicon_creator/rom_exts/rom_ext.c
index 806a5d8..375169a 100644
--- a/sw/device/silicon_creator/rom_exts/rom_ext.c
+++ b/sw/device/silicon_creator/rom_exts/rom_ext.c
@@ -9,10 +9,18 @@
 #include "sw/device/lib/dif/dif_uart.h"
 #include "sw/device/lib/runtime/hart.h"
 #include "sw/device/lib/runtime/print.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
 #include "sw/device/silicon_creator/lib/epmp_test_unlock.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"  // Generated.
 
+// Secure MMIO context.
+//
+// This is placed at a fixed location in memory within the .static_critical
+// section. It will be populated by the mask ROM before the jump to ROM_EXT.
+__attribute__((section(".static_critical.sec_mmio_ctx")))  //
+volatile sec_mmio_ctx_t sec_mmio_ctx;
+
 static dif_uart_t uart;
 
 int main(int argc, char *argv[]);
diff --git a/sw/device/silicon_creator/rom_exts/rom_ext_common.ld b/sw/device/silicon_creator/rom_exts/rom_ext_common.ld
index b498659..37e4414 100644
--- a/sw/device/silicon_creator/rom_exts/rom_ext_common.ld
+++ b/sw/device/silicon_creator/rom_exts/rom_ext_common.ld
@@ -81,13 +81,27 @@
   } > eflash
 
   /**
+   * Critical static data that is accessible by both the mask ROM and the ROM
+   * extension.
+   *
+   * Each variable added to .static_critical must be in its own subsection
+   * named after the variable.
+   *
+   * This data is not initialized during CRT (hence NOLOAD). Instead it will
+   * be initialized by the mask ROM.
+   */
+  .static_critical ORIGIN(ram_main) (NOLOAD) : ALIGN(4) {
+    INCLUDE sw/device/silicon_creator/lib/base/static_critical.ld
+  } > ram_main
+
+  /**
    * Mutable data section, at the bottom of ram_main. This will be initialized
    * from flash at runtime by the CRT.
    *
    * Load this by copying the bytes from [_data_init_start, _data_init_end] into
    * the range [_data_start, _data_end].
    */
-  .data ORIGIN(ram_main) : ALIGN(4) {
+  .data : ALIGN(4) {
     _data_start = .;
     _data_init_start = LOADADDR(.data);