add spi2 master controller test. now it can get jedec id from flash #3

resolved Conflicts:
diff --git a/target/ast10x0/peripherals/scu/pinctrl.rs b/target/ast10x0/peripherals/scu/pinctrl.rs
index d399716..9d90f54 100644
--- a/target/ast10x0/peripherals/scu/pinctrl.rs
+++ b/target/ast10x0/peripherals/scu/pinctrl.rs
@@ -537,6 +537,10 @@
     gen_pin_pairs!(SCU6B0, 0x6B0, 31);
 }
 
+// GPIO
+pub const PINCTRL_GPIOL2: &[PinctrlPin] = &[CLR_PIN_SCU418_26];
+pub const PINCTRL_GPIOL3: &[PinctrlPin] = &[CLR_PIN_SCU418_27];
+
 /// I2C1 pin group: SCL2/SDA2 mux selection on SCU414[30:31].
 ///
 /// The SVD names these EnblSCL2FnPin/EnblSDA2FnPin, but they correspond to
diff --git a/target/ast10x0/peripherals/scu/routing.rs b/target/ast10x0/peripherals/scu/routing.rs
index 0ed23f6..41a2868 100644
--- a/target/ast10x0/peripherals/scu/routing.rs
+++ b/target/ast10x0/peripherals/scu/routing.rs
@@ -3,27 +3,92 @@
 
 //! SCU routing and mux helpers for SPI monitor integration.
 
+use core::ptr::{read_volatile, write_volatile};
+
 use super::registers::ScuRegisters;
 use super::types::{
     Result, ScuExtMuxSelect, SpiMonitorInstance, SpiMonitorPassthrough, SpiMonitorSource,
 };
-const PIN_SPIM0_CLK_OUT_BIT: u32 = 7;
-const PIN_SPIM1_CLK_OUT_BIT: u32 = 21;
-const PIN_SPIM2_CLK_OUT_BIT: u32 = 3;
-const PIN_SPIM3_CLK_OUT_BIT: u32 = 17;
 
-pub type SpimGpioOriVal = [u32; 4];
+#[derive(Clone, Copy)]
+pub struct SpimGpioOriVal {
+    clk_gpio_ori_val: [u32; 4],
+}
 
-macro_rules! modify_reg {
-    ($reg:expr, $bit:expr, $clear:expr) => {{
-        let mut val: u32 = $reg.read().bits();
-        if $clear {
-            val &= !(1 << $bit);
-        } else {
-            val |= 1 << $bit;
-        }
-        $reg.write(|w| unsafe { w.bits(val) });
-    }};
+#[derive(Clone, Copy)]
+struct SpimGpioInfo {
+    scu_reg_addr: usize,
+    scu_bit_mask: u32,
+    gpio_addr: usize,
+    gpio_bit_mask: u32,
+}
+
+// Literal translation of g_ast1060_spim_clk_gpio[] in spi_aspeed.c.
+const AST1060_SPIM_CLK_GPIO: [SpimGpioInfo; 4] = [
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2690,
+        scu_bit_mask: 1 << 7,
+        gpio_addr: 0x7e78_0000,
+        gpio_bit_mask: 1 << 7,
+    },
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2690,
+        scu_bit_mask: 1 << 21,
+        gpio_addr: 0x7e78_0000,
+        gpio_bit_mask: 1 << 21,
+    },
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2694,
+        scu_bit_mask: 1 << 3,
+        gpio_addr: 0x7e78_0020,
+        gpio_bit_mask: 1 << 3,
+    },
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2694,
+        scu_bit_mask: 1 << 17,
+        gpio_addr: 0x7e78_0020,
+        gpio_bit_mask: 1 << 17,
+    },
+];
+
+// Literal translation of g_ast1060_spim_cs_gpio[] in spi_aspeed.c.
+const AST1060_SPIM_CS_GPIO: [SpimGpioInfo; 4] = [
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2690,
+        scu_bit_mask: 1 << 1,
+        gpio_addr: 0x7e78_0000,
+        gpio_bit_mask: 1 << 6,
+    },
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2690,
+        scu_bit_mask: 1 << 20,
+        gpio_addr: 0x7e78_0000,
+        gpio_bit_mask: 1 << 20,
+    },
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2694,
+        scu_bit_mask: 1 << 2,
+        gpio_addr: 0x7e78_0020,
+        gpio_bit_mask: 1 << 2,
+    },
+    SpimGpioInfo {
+        scu_reg_addr: 0x7e6e_2694,
+        scu_bit_mask: 1 << 16,
+        gpio_addr: 0x7e78_0020,
+        gpio_bit_mask: 1 << 16,
+    },
+];
+
+fn ast1060_spim_op_idx(scu0f0: u32) -> Option<usize> {
+    if scu0f0 & 0x7 == 0 {
+        return None;
+    }
+
+    match (scu0f0 & 0x7) - 1 {
+        2 => Some(3),
+        3 => Some(2),
+        _ => None,
+    }
 }
 
 impl ScuRegisters {
@@ -94,120 +159,103 @@
     pub fn spim_proprietary_pre_config(&self) -> Option<SpimGpioOriVal> {
         self.unlock_write_protection();
 
-        let scu = self.regs();
-        let gpio = unsafe { &*ast1060_pac::Gpio::ptr() };
+        let scu0f0 = self.regs().scu0f0().read().bits();
+        pw_log::debug!("SPIM pre-config: SCU0F0=0x{:08x}", scu0f0 as u32);
+        let op_idx = match ast1060_spim_op_idx(scu0f0) {
+            Some(idx) => idx,
+            None => return None,
+        };
+        pw_log::debug!(
+            "SPIM pre-config: active SPIM index {}, op index {}",
+            ((scu0f0 & 0x7) - 1) as u32,
+            op_idx as u32
+        );
 
-        let scu0f0 = scu.scu0f0().read().bits();
-        if scu0f0 & 0x7 == 0 {
-            return None;
+        let clk = AST1060_SPIM_CLK_GPIO[op_idx];
+        let cs = AST1060_SPIM_CS_GPIO[op_idx];
+        let mut clk_gpio_ori_val = [0u32; 4];
+
+        unsafe {
+            // Change the paired SPIM CLKOUT pin to GPIO mode.
+            let mut reg_val = read_volatile(clk.scu_reg_addr as *const u32);
+            reg_val &= !clk.scu_bit_mask;
+            write_volatile(clk.scu_reg_addr as *mut u32, reg_val);
+
+            // Save its GPIO direction bit, then configure it as an input.
+            let clk_dir_addr = (clk.gpio_addr + 0x4) as *mut u32;
+            reg_val = read_volatile(clk_dir_addr);
+            clk_gpio_ori_val[op_idx] = reg_val & clk.gpio_bit_mask;
+            reg_val &= !clk.gpio_bit_mask;
+            write_volatile(clk_dir_addr, reg_val);
+
+            // Drive the paired SPIM CSOUT GPIO high and configure it as output.
+            let cs_data_addr = cs.gpio_addr as *mut u32;
+            reg_val = read_volatile(cs_data_addr);
+            reg_val |= cs.gpio_bit_mask;
+            write_volatile(cs_data_addr, reg_val);
+
+            let cs_dir_addr = (cs.gpio_addr + 0x4) as *mut u32;
+            reg_val = read_volatile(cs_dir_addr);
+            reg_val |= cs.gpio_bit_mask;
+            write_volatile(cs_dir_addr, reg_val);
+
+            // Change the paired SPIM CSOUT pin to GPIO mode.
+            let cs_scu_addr = cs.scu_reg_addr as *mut u32;
+            reg_val = read_volatile(cs_scu_addr);
+            reg_val &= !cs.scu_bit_mask;
+            write_volatile(cs_scu_addr, reg_val);
         }
 
-        let spim_idx = (scu0f0 & 0x7) - 1;
-        if spim_idx > 3 {
-            return None;
-        }
-
-        let mut gpio_ori_val = [0; 4];
-
-        for idx in 0..4 {
-            if idx as u32 == spim_idx {
-                continue;
-            }
-
-            match idx {
-                0 => {
-                    modify_reg!(scu.scu690(), PIN_SPIM0_CLK_OUT_BIT, true);
-                    gpio_ori_val[0] = gpio.gpio004().read().bits();
-                    modify_reg!(gpio.gpio004(), PIN_SPIM0_CLK_OUT_BIT, true);
-                }
-                1 => {
-                    modify_reg!(scu.scu690(), PIN_SPIM1_CLK_OUT_BIT, true);
-                    gpio_ori_val[1] = gpio.gpio004().read().bits();
-                    modify_reg!(gpio.gpio004(), PIN_SPIM1_CLK_OUT_BIT, true);
-                }
-                2 => {
-                    modify_reg!(scu.scu694(), PIN_SPIM2_CLK_OUT_BIT, true);
-                    gpio_ori_val[2] = gpio.gpio024().read().bits();
-                    modify_reg!(gpio.gpio024(), PIN_SPIM2_CLK_OUT_BIT, true);
-                }
-                3 => {
-                    modify_reg!(scu.scu694(), PIN_SPIM3_CLK_OUT_BIT, true);
-                    gpio_ori_val[3] = gpio.gpio024().read().bits();
-                    modify_reg!(gpio.gpio024(), PIN_SPIM3_CLK_OUT_BIT, true);
-                }
-                _ => {}
-            }
-        }
-
-        Some(gpio_ori_val)
+        pw_log::debug!(
+            "SPIM pre-config: op index {}, saved CLK direction mask 0x{:08x}",
+            op_idx as u32,
+            clk_gpio_ori_val[op_idx] as u32
+        );
+        Some(SpimGpioOriVal {
+            clk_gpio_ori_val,
+        })
     }
 
     /// Restore AST1060 SPIM proprietary pin state after a transaction.
     pub fn spim_proprietary_post_config(&self, gpio_ori_val: SpimGpioOriVal) {
         self.unlock_write_protection();
 
-        let scu = self.regs();
-        let gpio = unsafe { &*ast1060_pac::Gpio::ptr() };
+        let scu0f0 = self.regs().scu0f0().read().bits();
+        let op_idx = match ast1060_spim_op_idx(scu0f0) {
+            Some(idx) => idx,
+            None => return,
+        };
+        let clk = AST1060_SPIM_CLK_GPIO[op_idx];
+        let cs = AST1060_SPIM_CS_GPIO[op_idx];
 
-        let bits = scu.scu0f0().read().bits();
-        if bits.trailing_zeros() >= 3 {
-            return;
+        pw_log::debug!(
+            "SPIM post-config: SCU0F0=0x{:08x}, op index {}, saved CLK direction mask 0x{:08x}",
+            scu0f0 as u32,
+            op_idx as u32,
+            gpio_ori_val.clk_gpio_ori_val[op_idx] as u32
+        );
+
+        unsafe {
+            // Restore the paired CLKOUT GPIO direction bit.
+            let clk_dir_addr = (clk.gpio_addr + 0x4) as *mut u32;
+            let mut reg_val = read_volatile(clk_dir_addr);
+            reg_val &= !clk.gpio_bit_mask;
+            reg_val |= gpio_ori_val.clk_gpio_ori_val[op_idx];
+            write_volatile(clk_dir_addr, reg_val);
+
+            // Return paired CLKOUT and CSOUT pins to SPIM mode.
+            let clk_scu_addr = clk.scu_reg_addr as *mut u32;
+            reg_val = read_volatile(clk_scu_addr);
+            reg_val |= clk.scu_bit_mask;
+            write_volatile(clk_scu_addr, reg_val);
+
+            let cs_scu_addr = cs.scu_reg_addr as *mut u32;
+            reg_val = read_volatile(cs_scu_addr);
+            reg_val |= cs.scu_bit_mask;
+            write_volatile(cs_scu_addr, reg_val);
         }
 
-        let spim_idx = (bits & 0x7) - 1;
-        if spim_idx > 3 {
-            return;
-        }
-
-        for idx in 0..4 {
-            if idx as u32 == spim_idx {
-                continue;
-            }
-
-            match idx {
-                0 => {
-                    let ori_val = gpio_ori_val[0];
-                    gpio.gpio004().modify(|r, w| unsafe {
-                        let mut current = r.bits();
-                        current &= !(1 << PIN_SPIM0_CLK_OUT_BIT);
-                        current |= ori_val;
-                        w.bits(current)
-                    });
-                    modify_reg!(scu.scu690(), PIN_SPIM0_CLK_OUT_BIT, false);
-                }
-                1 => {
-                    let ori_val = gpio_ori_val[1];
-                    gpio.gpio004().modify(|r, w| unsafe {
-                        let mut current = r.bits();
-                        current &= !(1 << PIN_SPIM1_CLK_OUT_BIT);
-                        current |= ori_val;
-                        w.bits(current)
-                    });
-                    modify_reg!(gpio.gpio004(), PIN_SPIM1_CLK_OUT_BIT, false);
-                }
-                2 => {
-                    let ori_val = gpio_ori_val[2];
-                    gpio.gpio024().modify(|r, w| unsafe {
-                        let mut current = r.bits();
-                        current &= !(1 << PIN_SPIM2_CLK_OUT_BIT);
-                        current |= ori_val;
-                        w.bits(current)
-                    });
-                    modify_reg!(scu.scu694(), PIN_SPIM2_CLK_OUT_BIT, false);
-                }
-                3 => {
-                    let ori_val = gpio_ori_val[3];
-                    gpio.gpio024().modify(|r, w| unsafe {
-                        let mut current = r.bits();
-                        current &= !(1 << PIN_SPIM3_CLK_OUT_BIT);
-                        current |= ori_val;
-                        w.bits(current)
-                    });
-                    modify_reg!(scu.scu694(), PIN_SPIM3_CLK_OUT_BIT, false);
-                }
-                _ => {}
-            }
-        }
+        pw_log::debug!("SPIM post-config: restore complete");
     }
 
     /// Select the external mux signal for a SPI monitor instance. Uses SCU0F0[15:12].
diff --git a/target/ast10x0/tests/smc/read/target_spi2.rs b/target/ast10x0/tests/smc/read/target_spi2.rs
new file mode 100644
index 0000000..9b9f56e
--- /dev/null
+++ b/target/ast10x0/tests/smc/read/target_spi2.rs
@@ -0,0 +1,242 @@
+// Licensed under the Apache-2.0 license
+// SPDX-License-Identifier: Apache-2.0
+
+//! AST10x0 SMC SPI2 read smoke test target.
+
+#![no_std]
+#![no_main]
+#[allow(unused_imports)]
+use ast10x0_peripherals::scu::{
+    pinctrl::{
+        PINCTRL_GPIOL2, PINCTRL_GPIOL3, PINCTRL_SPI2_QUAD, PINCTRL_SPIM3_DEFAULT,
+        PINCTRL_SPIM4_DEFAULT,
+    },
+    ScuRegisters, SpiMonitorInstance, SpiMonitorPassthrough, SpiMonitorSource, ScuExtMuxSelect,
+};
+use ast10x0_peripherals::smc::{
+    ChipSelect, FlashConfig, SmcConfig, SmcController, SmcError, SmcTopology, SpiTransaction,
+    SpiUninit, TransferMode,
+};
+use console_backend::console_backend_write_all;
+use core::ptr::{read_volatile, write_volatile};
+use target_common::{declare_target, TargetInterface};
+use {console_backend as _, entry as _};
+
+#[path = "../target_debug.rs"]
+mod target_debug;
+use target_debug::{dump_smc_read, dump_smc_register};
+
+const SPI_FLASH_CONFIG: FlashConfig = FlashConfig {
+    capacity_mb: 32,
+    page_size: 256,
+    sector_size: 4096,
+    block_size: 65536,
+    spi_clock_mhz: 25,
+};
+
+pub struct Target {}
+/*
+SCU418  = 0x7E6E_2418, clear bits 26, 27
+GPIO070 = 0x7E78_0070, set bits 26, 27
+GPIO074 = 0x7E78_0074, set bits 26, 27
+*/
+fn gpio_flash_power() {
+    // const SCU418: *mut u32 = 0x7E6E_2418 as *mut u32;
+    const GPIO_DATA: *mut u32 = 0x7E78_0070 as *mut u32;
+    const GPIO_DIR: *mut u32 = 0x7E78_0074 as *mut u32;
+    const GPIOL2_L3_MASK: u32 = (1 << 26) | (1 << 27);
+
+    unsafe {
+        // Select GPIO function for GPIOL2/GPIOL3.
+        // write_volatile(SCU418, read_volatile(SCU418) & !GPIOL2_L3_MASK);
+        // Configure GPIOL2/GPIOL3 as outputs and drive them high.
+        write_volatile(GPIO_DIR, read_volatile(GPIO_DIR) | GPIOL2_L3_MASK);
+        write_volatile(GPIO_DATA, read_volatile(GPIO_DATA) | GPIOL2_L3_MASK);
+    }
+
+    for _ in 0..1_000_000 {
+        core::hint::spin_loop();
+    }
+}
+
+// Temporary raw-MMIO implementation until GPIO and SGPIOM peripherals exist.
+#[allow(dead_code)]
+fn configure_spi2_external_mux(select_mux1: bool) {
+    const SCU41C: *mut u32 = 0x7E6E_241C as *mut u32;
+    const SGPIOM_PIN_MASK: u32 = 0xF << 8;
+
+    const GPIO_E_H_DATA: *mut u32 = 0x7E78_0020 as *mut u32;
+    const GPIO_E_H_DIR: *mut u32 = 0x7E78_0024 as *mut u32;
+    const GPIO_E8: u32 = 1 << 8;
+
+    const SGPIOM_DATA_A_D: *mut u32 = 0x7E78_0500 as *mut u32;
+    const SGPIOM_CONFIG: *mut u32 = 0x7E78_0554 as *mut u32;
+    const SGPIOM_WRITE_LATCH_A_D: *const u32 = 0x7E78_0570 as *const u32;
+    const SGPIOM_A_D_2: u32 = 1 << 2;
+    const SGPIOM_CONFIG_MASK: u32 = 1 | (0x1F << 6) | (0xFFFF << 16);
+    const SGPIOM_CONFIG_1MHZ_128_PINS: u32 = 1 | (16 << 6) | (24 << 16);
+
+    unsafe {
+        // Select the SGPIOM physical pins and initialize the controller using
+        // the same 1 MHz / 128-pin settings as the Zephyr board configuration.
+        write_volatile(SCU41C, read_volatile(SCU41C) | SGPIOM_PIN_MASK);
+        let config = read_volatile(SGPIOM_CONFIG) & !SGPIOM_CONFIG_MASK;
+        write_volatile(
+            SGPIOM_CONFIG,
+            config | SGPIOM_CONFIG_1MHZ_128_PINS,
+        );
+
+        let mut gpio_data = read_volatile(GPIO_E_H_DATA);
+        let mut sgpio_data = read_volatile(SGPIOM_WRITE_LATCH_A_D);
+        if select_mux1 {
+            gpio_data |= GPIO_E8;
+            sgpio_data |= SGPIOM_A_D_2;
+        } else {
+            gpio_data &= !GPIO_E8;
+            sgpio_data &= !SGPIOM_A_D_2;
+        }
+
+        write_volatile(GPIO_E_H_DATA, gpio_data);
+        write_volatile(GPIO_E_H_DIR, read_volatile(GPIO_E_H_DIR) | GPIO_E8);
+        write_volatile(SGPIOM_DATA_A_D, sgpio_data);
+    }
+
+    // Match the overlay's ext-mux-sel-delay-us = <1000>.
+    for _ in 0..100_000 {
+        core::hint::spin_loop();
+    }
+}
+
+fn config_spi2_master_controller() -> Result<(), SmcError> {
+    let scu = unsafe { ScuRegisters::new_global_unlocked() };
+    scu.apply_pinctrl_group(PINCTRL_SPIM3_DEFAULT);
+    scu.apply_pinctrl_group(PINCTRL_SPIM4_DEFAULT);
+    scu.apply_pinctrl_group(PINCTRL_SPI2_QUAD);
+    scu.apply_pinctrl_group(PINCTRL_GPIOL2);
+    scu.apply_pinctrl_group(PINCTRL_GPIOL3);
+    gpio_flash_power();
+    //configure spi2 external mux through gpio pins
+    configure_spi2_external_mux(true);
+
+    // Configure the mux for the SPI master controller path.
+    scu.set_spim_internal_master_route(SpiMonitorInstance::Spim2, SpiMonitorSource::Spi2);
+    scu.set_spim_passthrough(SpiMonitorInstance::Spim2, SpiMonitorPassthrough::Enabled);
+    scu.set_spim_ext_mux(SpiMonitorInstance::Spim2, ScuExtMuxSelect::Mux1);
+    pw_log::info!("SCU pinmux and SPIM routing configured for SPI2 monitoring");
+    unsafe {
+        write_volatile(0x7E6E_20F0 as *mut u32, 0xfff0);
+    }
+    for _ in 0..1_000_000 {
+        core::hint::spin_loop();
+    }
+    Ok(())
+}
+
+fn run_spi2_read_test() -> Result<(), SmcError> {
+    config_spi2_master_controller()?;
+
+    let config = SmcConfig {
+        controller_id: SmcController::Spi2,
+        cs0: Some(SPI_FLASH_CONFIG),
+        cs1: None,
+        dma_enabled: true,
+        enable_interrupts: false,
+        topology: SmcTopology::NormalSpi { master_idx: 2 },
+    };
+
+    pw_log::info!("=== AST10x0 SMC SPI2 read test ===");
+    let spi = unsafe { SpiUninit::new(SmcController::Spi2, config)? };
+    let mut spi = spi.init()?;
+    spi.spi_nor_read_init(ChipSelect::Cs0)?;
+
+    if !spi.is_ready() {
+        return Err(SmcError::HardwareError);
+    }
+
+    pw_log::info!("=== SPI2 controller register ===");
+    dump_smc_register(0x7E64_0000, 16);
+    dump_smc_register(0x7E64_0080, 16);
+    pw_log::info!("=== SCU QSPI Mux routing register ===");
+    dump_smc_register(0x7E6E_20F0, 2);
+    dump_smc_register(0x7E6E_2418, 2);
+    dump_smc_register(0x7e6e_2694, 2);
+    dump_smc_register(0x7E78_0020, 2);
+    dump_smc_register(0x7E78_0070, 2);
+    let mut jedec = [0u8; 3];
+    SpiTransaction::transceive_user_with_spim(
+        &mut spi,
+        SpiMonitorInstance::Spim2,
+        ChipSelect::Cs0,
+        &[0x9f],
+        &[],
+        &mut jedec,
+        TransferMode::Mode111,
+    )?;
+    pw_log::info!(
+        "SPI2 CS0 JEDEC ID: {:02x} {:02x} {:02x}",
+        jedec[0] as u32,
+        jedec[1] as u32,
+        jedec[2] as u32
+    );
+
+    if jedec[0] == 0xff {
+        pw_log::info!("SPI2 CS0 JEDEC manufacturer is 0xff; skipping read test");
+        return Ok(());
+    }
+
+    pw_log::info!("=== SPI2 read ===");
+    let mut buf = [0u8; 64];
+    let n = SpiTransaction::read_with_spim(
+        &mut spi,
+        SpiMonitorInstance::Spim2,
+        ChipSelect::Cs0,
+        0x0,
+        &mut buf,
+    )?;
+    if n != buf.len() {
+        return Err(SmcError::HardwareError);
+    }
+    dump_smc_read(&buf, buf.len() as u32);
+
+    pw_log::info!("=== SPI2 DMA read @ 0x00000000 ===");
+    let dma_buf = unsafe { core::slice::from_raw_parts_mut(0x41500 as *mut u8, 256) };
+    let mut dma_txn = SpiTransaction::dma_read_with_spim(
+        &mut spi,
+        SpiMonitorInstance::Spim2,
+        ChipSelect::Cs0,
+        0x0,
+        0x41500usize,
+        dma_buf.len() as u32,
+    )?;
+
+    loop {
+        match dma_txn.poll_dma_completion() {
+            core::task::Poll::Pending => {}
+            core::task::Poll::Ready(result) => {
+                result?;
+                break;
+            }
+        }
+    }
+    dump_smc_read(dma_buf, dma_buf.len() as u32);
+
+    Ok(())
+}
+
+impl TargetInterface for Target {
+    const NAME: &'static str = "AST10x0 SMC SPI2 read Test";
+
+    fn main() -> ! {
+        let sentinel = if run_spi2_read_test().is_ok() {
+            b"TEST_RESULT:PASS\n"
+        } else {
+            b"TEST_RESULT:FAIL\n"
+        };
+        let _ = console_backend_write_all(sentinel);
+
+        #[expect(clippy::empty_loop)]
+        loop {}
+    }
+}
+
+declare_target!(Target);