[test] Add rom_e2e_bootstrap_phase2_read

Fixes #14466

Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/rom/data/rom_testplan.hjson b/sw/device/silicon_creator/rom/data/rom_testplan.hjson
index a0a0856..e66f216 100644
--- a/sw/device/silicon_creator/rom/data/rom_testplan.hjson
+++ b/sw/device/silicon_creator/rom/data/rom_testplan.hjson
@@ -447,15 +447,14 @@
 
             - Apply bootstrap pin strapping and reset the chip.
             - Send `CHIP_ERASE` (`0xc7`).
-            - Write `0x4552544f` (ASCII "OTRE") at byte offset `0x334`.
-            - Reset the chip.
-            - Verify that the chip outputs the expected `BFV`: `024d410d` over UART.
-              - ROM will continously reset the chip and output the same `BFV` and `LCV`.
-            - Apply bootstrap pin strapping and reset the chip.
-            - Send `READ` (`0x03`) followed by the 3-byte address 0x000334.
+            - Write `0x4552544f_00000000` (ASCII "\0\0\0\0OTRE") at byte offset `0x80330`.
+              - Note: Writes must start at a flash-word-aligned address and we must write to the second slot since ROM returns the last error.
+            - `READ` (`0x03`) 8 bytes starting at `0x080330`.
               - This is the address of the identifier that was written earlier.
-            - Verify that the chip does not respond for the next 4 bytes.
-              - The data on the CIPO line must be `0xff`.
+            - Verify that the response is not equal to `0x4552544f_00000000`.
+            - Release pins and reset.
+            - Verify that the chip outputs the expected `BFV`: `0242500d` over UART (`kErrorBootPolicyBadLength`).
+              - ROM will continously reset the chip and output the same `BFV` and `LCV`.
             '''
       tags: ["rom", "verilator", "dv", "fpga", "silicon"]
       stage: V2
diff --git a/sw/host/tests/rom/e2e_bootstrap_entry/src/main.rs b/sw/host/tests/rom/e2e_bootstrap_entry/src/main.rs
index 3e19085..70c3c7e 100644
--- a/sw/host/tests/rom/e2e_bootstrap_entry/src/main.rs
+++ b/sw/host/tests/rom/e2e_bootstrap_entry/src/main.rs
@@ -530,6 +530,40 @@
     Ok(())
 }
 
+fn test_bootstrap_phase2_read(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
+    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;
+    let spi = transport.spi("0")?;
+    let uart = transport.uart("0")?;
+    let mut read_buf = [0u8; 8];
+
+    SpiFlash::from_spi(&*spi)?
+        // Send CHIP_ERASE to transition to phase 2.
+        .chip_erase(&*spi)?
+        // Write "OTRE" to the identifier field of the manifest in the second slot.
+        .program(&*spi, 0x80330, &0x4552544f_00000000u64.to_le_bytes())?
+        // Read 8 bytes starting from 0x80330.
+        .read(&*spi, 0x80330, &mut read_buf)?;
+    let received = u64::from_le_bytes(read_buf);
+    log::info!("Received: {:#x}", received);
+    assert_ne!(received, 0x4552544f_00000000u64);
+
+    let mut console = UartConsole {
+        timeout: Some(Duration::new(1, 0)),
+        // `kErrorBootPolicyBadLength` (0242500d) is defined in `error.h`.
+        exit_success: Some(Regex::new("BFV:0242500d\r\n")?),
+        ..Default::default()
+    };
+    // Remove strapping so that chip fails to boot instead of going into bootstrap.
+    transport.remove_pin_strapping("ROM_BOOTSTRAP")?;
+    transport.reset_target(opts.init.bootstrap.options.reset_delay, true)?;
+    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
+    if result != ExitStatus::ExitSuccess {
+        bail!("FAIL: {:?}", result);
+    }
+
+    Ok(())
+}
+
 fn main() -> Result<()> {
     let opts = Opts::from_args();
     opts.init.init_logging();
@@ -559,6 +593,7 @@
     for erase_cmd in [SpiFlash::SECTOR_ERASE, SpiFlash::CHIP_ERASE] {
         execute_test!(test_bootstrap_phase2_erase, &opts, &transport, erase_cmd);
     }
+    execute_test!(test_bootstrap_phase2_read, &opts, &transport);
 
     Ok(())
 }