[flash_ctrl] Add plain text integrity in flash

- Fixes https://github.com/lowRISC/opentitan/issues/8984
- Takes the spare storage bits of flash and store a de-scrambled
  integrity. This allows flash to emulate the behavior of end-to-end
  storage despite its need for ECC reliability checks.

Signed-off-by: Timothy Chen <timothytim@google.com>

[sw, util] Add support for flash image generation

- only supports the plain text ECC at the moment
- scrambled will be added in the future

Signed-off-by: Timothy Chen <timothytim@google.com>

[test] update verilator CI test pathing

flash now uses vmem instead of elf

Signed-off-by: Timothy Chen <timothytim@google.com>

[flash_ctrl] python updates per comments

Signed-off-by: Timothy Chen <timothytim@google.com>

[flash_ctrl] fix typo

Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/sw/device/benchmarks/coremark/meson.build b/sw/device/benchmarks/coremark/meson.build
index 2139582..b3cce1c 100644
--- a/sw/device/benchmarks/coremark/meson.build
+++ b/sw/device/benchmarks/coremark/meson.build
@@ -62,6 +62,15 @@
     kwargs: bin_to_vmem64_custom_target_args,
   )
 
+  coremark_top_earlgrey_scr_vmem64 = custom_target(
+    target_name.format('scrambled'),
+    input: coremark_top_earlgrey_vmem64,
+    output: flash_image_outputs,
+    command: flash_image_command,
+    depend_files: flash_image_depend_files,
+    build_by_default: true,
+  )
+
   custom_target(
     target_name.format('export'),
     command: export_target_command,
diff --git a/sw/device/examples/hello_usbdev/meson.build b/sw/device/examples/hello_usbdev/meson.build
index 1e673bb..750ed4f 100644
--- a/sw/device/examples/hello_usbdev/meson.build
+++ b/sw/device/examples/hello_usbdev/meson.build
@@ -53,6 +53,15 @@
     kwargs: bin_to_vmem64_custom_target_args,
   )
 
+  hello_usbdev_scr_vmem64 = custom_target(
+    target_name.format('scrambled'),
+    input: hello_usbdev_vmem64,
+    output: flash_image_outputs,
+    command: flash_image_command,
+    depend_files: flash_image_depend_files,
+    build_by_default: true,
+  )
+
   custom_target(
     target_name.format('export'),
     command: export_target_command,
@@ -63,6 +72,7 @@
       hello_usbdev_bin,
       hello_usbdev_vmem32,
       hello_usbdev_vmem64,
+      hello_usbdev_scr_vmem64,
     ],
     output: target_name.format('export'),
     build_always_stale: true,
diff --git a/sw/device/examples/hello_world/meson.build b/sw/device/examples/hello_world/meson.build
index a644745..903a581 100644
--- a/sw/device/examples/hello_world/meson.build
+++ b/sw/device/examples/hello_world/meson.build
@@ -50,6 +50,15 @@
     kwargs: bin_to_vmem64_custom_target_args,
   )
 
+  hello_world_scr_vmem64 = custom_target(
+    target_name.format('scrambled'),
+    input: hello_world_vmem64,
+    output: flash_image_outputs,
+    command: flash_image_command,
+    depend_files: flash_image_depend_files,
+    build_by_default: true,
+  )
+
   custom_target(
     target_name.format('export'),
     command: export_target_command,
@@ -60,6 +69,7 @@
       hello_world_bin,
       hello_world_vmem32,
       hello_world_vmem64,
+      hello_world_scr_vmem64,
     ],
     output: target_name.format('export'),
     build_always_stale: true,
diff --git a/sw/device/lib/flash_ctrl.c b/sw/device/lib/flash_ctrl.c
index 6fb776e..83faf7b 100644
--- a/sw/device/lib/flash_ctrl.c
+++ b/sw/device/lib/flash_ctrl.c
@@ -227,6 +227,8 @@
                 << FLASH_CTRL_MP_REGION_CFG_SHADOWED_0_ERASE_EN_0_BIT |
             region_cfg->scramble_en
                 << FLASH_CTRL_MP_REGION_CFG_SHADOWED_0_SCRAMBLE_EN_0_BIT |
+            region_cfg->ecc_en
+                << FLASH_CTRL_MP_REGION_CFG_SHADOWED_0_ECC_EN_0_BIT |
             0x1 << FLASH_CTRL_MP_REGION_CFG_SHADOWED_0_EN_0_BIT);
   } else if (region_cfg->part == kInfoPartition) {
     reg_value =
@@ -238,6 +240,8 @@
             << FLASH_CTRL_BANK0_INFO0_PAGE_CFG_SHADOWED_0_ERASE_EN_0_BIT |
         region_cfg->scramble_en
             << FLASH_CTRL_BANK0_INFO0_PAGE_CFG_SHADOWED_0_SCRAMBLE_EN_0_BIT |
+        region_cfg->ecc_en
+            << FLASH_CTRL_BANK0_INFO0_PAGE_CFG_SHADOWED_0_ECC_EN_0_BIT |
         0x1 << FLASH_CTRL_BANK0_INFO0_PAGE_CFG_SHADOWED_0_EN_0_BIT;
 
     bank_sel = region_cfg->base / flash_get_pages_per_bank();
diff --git a/sw/device/lib/flash_ctrl.h b/sw/device/lib/flash_ctrl.h
index 93aa2a3..e812cdd 100644
--- a/sw/device/lib/flash_ctrl.h
+++ b/sw/device/lib/flash_ctrl.h
@@ -45,8 +45,10 @@
   uint32_t prog_en;
   /** Erase enable flag. */
   uint32_t erase_en;
-  /** Scramble / ECC enable flag. */
+  /** Scramble enable flag*/
   uint32_t scramble_en;
+  /** ECC enable flag. */
+  uint32_t ecc_en;
 } mp_region_t;
 
 /**
diff --git a/sw/device/meson.build b/sw/device/meson.build
index 3bcbf66..ed9b592 100644
--- a/sw/device/meson.build
+++ b/sw/device/meson.build
@@ -135,6 +135,25 @@
     scramble_image_hjson
 ]
 
+# Generate proper flash image
+#
+
+flash_image_outputs = [
+  '@BASENAME@.scr.vmem',
+]
+
+flash_image_command = [
+    prog_python,
+    meson.source_root() / 'util/design/gen-flash-img.py',
+    '@INPUT@',
+    '@OUTPUT@',
+]
+
+flash_image_depend_files = [
+    meson.source_root() / 'util/design/gen-flash-img.py',
+]
+
+
 # Signing keys for ROM_EXT images.
 signing_keys = {
   'fpga_key_0': {
diff --git a/sw/device/sca/meson.build b/sw/device/sca/meson.build
index 84ac50b..13da5c1 100644
--- a/sw/device/sca/meson.build
+++ b/sw/device/sca/meson.build
@@ -82,6 +82,15 @@
       kwargs: bin_to_vmem64_custom_target_args,
     )
 
+    sca_program_scr_vmem64 = custom_target(
+      target_name.format('scrambled'),
+      input: sca_program_vmem64,
+      output: flash_image_outputs,
+      command: flash_image_command,
+      depend_files: flash_image_depend_files,
+      build_by_default: true,
+    )
+
     custom_target(
       target_name.format('export'),
       command: export_target_command,
@@ -92,6 +101,7 @@
         sca_program_bin,
         sca_program_vmem32,
         sca_program_vmem64,
+        sca_program_scr_vmem64,
       ],
       output: target_name.format('export'),
       build_always_stale: true,
diff --git a/sw/device/silicon_creator/rom_ext/meson.build b/sw/device/silicon_creator/rom_ext/meson.build
index 299a4e0..886c1e8 100644
--- a/sw/device/silicon_creator/rom_ext/meson.build
+++ b/sw/device/silicon_creator/rom_ext/meson.build
@@ -176,10 +176,20 @@
         kwargs: bin_to_vmem64_custom_target_args,
       )
 
+      rom_ext_signed_scr_vmem64 = custom_target(
+        signed_target_name.format('scrambled'),
+        input: rom_ext_signed_vmem64,
+        output: flash_image_outputs,
+        command: flash_image_command,
+        depend_files: flash_image_depend_files,
+        build_by_default: true,
+      )
+
       targets_to_export += [
         rom_ext_signed_bin,
         rom_ext_signed_vmem32,
         rom_ext_signed_vmem64,
+        rom_ext_signed_scr_vmem64,
       ]
     endforeach
 
diff --git a/sw/device/silicon_creator/testing/meson.build b/sw/device/silicon_creator/testing/meson.build
index ccb54fc..9f3adae 100644
--- a/sw/device/silicon_creator/testing/meson.build
+++ b/sw/device/silicon_creator/testing/meson.build
@@ -53,6 +53,15 @@
       kwargs: bin_to_vmem64_custom_target_args,
     )
 
+    mask_rom_test_scr_vmem64 = custom_target(
+      target_name.format('scrambled'),
+      input: mask_rom_test_vmem64,
+      output: flash_image_outputs,
+      command: flash_image_command,
+      depend_files: flash_image_depend_files,
+      build_by_default: true,
+    )
+
     mask_rom_test_sim_dv_frames = []
     if device_name == 'sim_dv' and \
         mask_rom_test_info.has_key('dv_frames') and mask_rom_test_info['dv_frames']
@@ -112,6 +121,7 @@
         mask_rom_test_bin,
         mask_rom_test_vmem32,
         mask_rom_test_vmem64,
+        mask_rom_test_scr_vmem64,
         mask_rom_test_sim_dv_frames,
         mask_rom_test_sim_dv_logs,
       ],
diff --git a/sw/device/tests/flash_ctrl_test.c b/sw/device/tests/flash_ctrl_test.c
index 66dedc7..d6fc08a 100644
--- a/sw/device/tests/flash_ctrl_test.c
+++ b/sw/device/tests/flash_ctrl_test.c
@@ -47,6 +47,7 @@
                              .rd_en = true,
                              .prog_en = true,
                              .erase_en = true,
+                             .ecc_en = true,
                              .scramble_en = true};
   flash_cfg_region(&info_region);
 
@@ -58,6 +59,7 @@
                              .rd_en = true,
                              .prog_en = true,
                              .erase_en = true,
+                             .ecc_en = true,
                              .scramble_en = true};
   flash_cfg_region(&data_region);
 
@@ -135,6 +137,7 @@
                                    .rd_en = true,
                                    .prog_en = true,
                                    .erase_en = true,
+                                   .ecc_en = true,
                                    .scramble_en = false};
 
   uintptr_t ok_region_start =
diff --git a/sw/device/tests/meson.build b/sw/device/tests/meson.build
index 6daccac..c87047d 100644
--- a/sw/device/tests/meson.build
+++ b/sw/device/tests/meson.build
@@ -652,6 +652,15 @@
       kwargs: bin_to_vmem64_custom_target_args,
     )
 
+    sw_test_scr_vmem64 = custom_target(
+      target_name.format('scrambled'),
+      input: sw_test_vmem64,
+      output: flash_image_outputs,
+      command: flash_image_command,
+      depend_files: flash_image_depend_files,
+      build_by_default: true,
+    )
+
     sw_test_sim_dv_frames = []
     if device_name == 'sim_dv' and \
         sw_test_info.has_key('dv_frames') and sw_test_info['dv_frames']
@@ -711,6 +720,7 @@
         sw_test_bin,
         sw_test_vmem32,
         sw_test_vmem64,
+        sw_test_scr_vmem64,
         sw_test_sim_dv_frames,
         sw_test_sim_dv_logs,
       ],
@@ -788,10 +798,20 @@
         kwargs: bin_to_vmem64_custom_target_args,
       )
 
+      sw_test_signed_scr_vmem64 = custom_target(
+        signed_target_name.format('scrambled'),
+        input: sw_test_signed_vmem64,
+        output: flash_image_outputs,
+        command: flash_image_command,
+        depend_files: flash_image_depend_files,
+        build_by_default: true,
+      )
+
       targets_to_export += [
         sw_test_signed_bin,
         sw_test_signed_vmem32,
         sw_test_signed_vmem64,
+        sw_test_signed_scr_vmem64
       ]
     endforeach
 
@@ -853,6 +873,15 @@
     kwargs: bin_to_vmem64_custom_target_args,
   )
 
+  crt_test_scr_vmem64 = custom_target(
+    target_name.format('scrambled'),
+    input: crt_test_vmem64,
+    output: flash_image_outputs,
+    command: flash_image_command,
+    depend_files: flash_image_depend_files,
+    build_by_default: true,
+  )
+
   custom_target(
     target_name.format('export'),
     command: export_target_command,
@@ -863,6 +892,7 @@
       crt_test_bin,
       crt_test_vmem32,
       crt_test_vmem64,
+      crt_test_scr_vmem64,
     ],
     output: target_name.format('export'),
     build_always_stale: true,
@@ -909,6 +939,15 @@
     kwargs: bin_to_vmem64_custom_target_args,
   )
 
+  ottf_scr_vmem64 = custom_target(
+    target_name.format('scrambled'),
+    input: ottf_vmem64,
+    output: flash_image_outputs,
+    command: flash_image_command,
+    depend_files: flash_image_depend_files,
+    build_by_default: true,
+  )
+
   custom_target(
     target_name.format('export'),
     command: export_target_command,
@@ -919,6 +958,7 @@
       ottf_bin,
       ottf_vmem32,
       ottf_vmem64,
+      ottf_scr_vmem64
     ],
     output: target_name.format('export'),
     build_always_stale: true,