add spimonitor test.
Spimonitor is not monitoring the traffic from spi controller.
Spi monitor is only monitoring the traffic from either BMC or host.
diff --git a/target/ast10x0/board/src/lib.rs b/target/ast10x0/board/src/lib.rs
index 8e85720..78c5ab8 100644
--- a/target/ast10x0/board/src/lib.rs
+++ b/target/ast10x0/board/src/lib.rs
@@ -21,7 +21,7 @@
 pub use monitor::Ast1060Monitor;
 pub use spim_wiring::{
     apply_spim_external_mux, apply_spim_pinctrl, apply_spim_wiring, apply_spim_wiring_with_log,
-    presets, SpimWiring, SpimWiringError,
+    presets, spim_external_mux_state, SpimWiring, SpimWiringError,
 };
 
 pub use ast10x0_peripherals::i2c::{I2cConfig, I2cError};
diff --git a/target/ast10x0/board/src/spim_wiring.rs b/target/ast10x0/board/src/spim_wiring.rs
index ed247fd..1348917 100644
--- a/target/ast10x0/board/src/spim_wiring.rs
+++ b/target/ast10x0/board/src/spim_wiring.rs
@@ -4,8 +4,8 @@
 //! Static SPI-monitor wiring for AST10x0 boards.
 //!
 //! Composes the `scu::routing` mux helpers with the `spimonitor::controller`
-//! typestate to apply once-per-process SPIM routing and SPIPF policy at
-//! backend init time. Per-transaction reroutes are explicitly out of scope:
+//! typestate to apply once-per-process external-monitor routing and SPIPF
+//! policy at backend init time. Per-transaction reroutes are explicitly out of scope:
 //! the SPIPF lock is one-way, and the design doc
 //! (`peripherals/spimonitor/planning/overview-and-usage-model.md`) calls for
 //! "configure early, validate, lock, and operate under that locked policy."
@@ -25,16 +25,15 @@
 };
 use ast1060_pac as device;
 
-/// Static SPIM wiring for one SPI controller.
+/// Static wiring for one external SPI monitor path.
 ///
-/// Captures the four SCU0F0 fields plus the MISO multi-function pin choice
-/// that together determine which monitor instance a given SPI master is
-/// routed through.
+/// The `source` identifies the external flash bus associated with this policy.
+/// It does not enable the AST1060 internal SPI-master detour.
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub struct SpimWiring {
-    /// Monitor instance the master is routed through.
+    /// Monitor instance connected to the external bus.
     pub instance: SpiMonitorInstance,
-    /// Which SPI master is being routed.
+    /// External SPI bus associated with the monitor policy.
     pub source: SpiMonitorSource,
     /// Passthrough enable for the chosen instance.
     pub passthrough: SpiMonitorPassthrough,
@@ -127,6 +126,17 @@
     };
 
     let gpio = unsafe { &*device::Gpio::ptr() };
+    let scu = unsafe { &*device::Scu::ptr() };
+    scu.scu41c().modify(|_, w| {
+        w.enbl_sgpiomaster_ckfn_pin()
+            .set_bit()
+            .enbl_sgpiomaster_ldfn_pin()
+            .set_bit()
+            .enbl_sgpiomaster_dofn_pin()
+            .set_bit()
+            .enbl_sgpiomaster_difn_pin()
+            .set_bit()
+    });
     match gpio_group {
         ExternalMuxGpioGroup::Abcd => {
             gpio.gpio000().modify(|r, w| unsafe {
@@ -147,13 +157,51 @@
     }
 
     let sgpio = unsafe { &*device::Sgpiom::ptr() };
-    sgpio.gpio500().modify(|r, w| unsafe {
-        w.bits(update_bit(r.bits(), sgpio_mask, high))
+    sgpio.gpio554().modify(|_, w| unsafe {
+        w.enbl_of_serial_gpio()
+            .set_bit()
+            .numbers_of_serial_gpiopins()
+            .bits(16)
+            .serial_gpioclk_division()
+            .bits(24)
     });
+    let latch = sgpio.gpio570().read().bits();
+    sgpio
+        .gpio500()
+        .write(|w| unsafe { w.bits(update_bit(latch, sgpio_mask, high)) });
 
     crate::delay_us(1_000);
 }
 
+/// Read back the two board-level external mux-select outputs.
+#[must_use]
+pub fn spim_external_mux_state(
+    instance: SpiMonitorInstance,
+) -> Option<ScuExtMuxSelect> {
+    let (gpio_group, gpio_mask, sgpio_mask) = match instance {
+        SpiMonitorInstance::Spim0 | SpiMonitorInstance::Spim1 => {
+            (ExternalMuxGpioGroup::Abcd, 1 << 12, 1 << 0)
+        }
+        SpiMonitorInstance::Spim2 | SpiMonitorInstance::Spim3 => {
+            (ExternalMuxGpioGroup::Efgh, 1 << 8, 1 << 2)
+        }
+    };
+    let gpio = unsafe { &*device::Gpio::ptr() };
+    let gpio_high = match gpio_group {
+        ExternalMuxGpioGroup::Abcd => gpio.gpio000().read().bits() & gpio_mask != 0,
+        ExternalMuxGpioGroup::Efgh => gpio.gpio020().read().bits() & gpio_mask != 0,
+    };
+    let sgpio = unsafe { &*device::Sgpiom::ptr() };
+    let sgpio_high = sgpio.gpio570().read().bits() & sgpio_mask != 0;
+    if gpio_high != sgpio_high {
+        None
+    } else if gpio_high {
+        Some(ScuExtMuxSelect::Mux1)
+    } else {
+        Some(ScuExtMuxSelect::Mux0)
+    }
+}
+
 #[derive(Clone, Copy)]
 enum ExternalMuxGpioGroup {
     Abcd,
@@ -205,7 +253,9 @@
 
     apply_spim_pinctrl(scu, wiring.instance);
     scu.disable_spim_cs_internal_pull_down(wiring.instance);
-    scu.set_spim_internal_master_route(wiring.instance, wiring.source);
+    // SPIPF monitors the external BMC/host pins. Keep SCU0F0[3:0] clear so
+    // neither AST1060 internal SPI controller is detoured into the monitor.
+    scu.set_spim_internal_mux(wiring.source, 0)?;
     scu.set_spim_passthrough(wiring.instance, wiring.passthrough);
     scu.set_spim_ext_mux(wiring.instance, wiring.ext_mux);
     apply_spim_external_mux(wiring.instance, wiring.ext_mux);
diff --git a/target/ast10x0/peripherals/spimonitor/commands.rs b/target/ast10x0/peripherals/spimonitor/commands.rs
index 034b7a3..40dbb86 100644
--- a/target/ast10x0/peripherals/spimonitor/commands.rs
+++ b/target/ast10x0/peripherals/spimonitor/commands.rs
@@ -142,4 +142,16 @@
     fn winbond_die_select_matches_zephyr_encoding() {
         assert_eq!(table_value(0xc2, false), Some(0x7100_00c2));
     }
+
+    #[test]
+    fn complete_zephyr_allow_list_is_supported() {
+        let commands = [
+            0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21,
+            0x9f, 0x5a, 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x3b, 0x3c, 0x70,
+            0xbb, 0xbc, 0x50, 0xeb, 0xec, 0xc2,
+        ];
+        for command in commands {
+            assert!(table_value(command, false).is_some());
+        }
+    }
 }
diff --git a/target/ast10x0/peripherals/spimonitor/controller.rs b/target/ast10x0/peripherals/spimonitor/controller.rs
index 123f1de..a6f80e9 100644
--- a/target/ast10x0/peripherals/spimonitor/controller.rs
+++ b/target/ast10x0/peripherals/spimonitor/controller.rs
@@ -178,6 +178,117 @@
 // ---------------------------------------------------------------------------
 
 impl SpiMonitor<Configured> {
+    /// Add or re-enable one command, matching the Zephyr shell `cmd add`.
+    pub fn add_command(&self, opcode: u8, valid_once: bool) -> Result<usize> {
+        let value =
+            table_value(opcode, valid_once).ok_or(SpiMonitorError::UnsupportedCommand(opcode))?;
+
+        for slot in 0..COMMAND_TABLE_SLOTS {
+            let current = self.regs.read_allow_cmd_slot(slot);
+            if current & 0xff == u32::from(opcode) && current & COMMAND_LOCKED == 0 {
+                self.regs.write_allow_cmd_slot(slot, value);
+                return verify_command_slot(&self.regs, slot, value);
+            }
+        }
+
+        let slot = if let Some(slot) = fixed_slot(opcode) {
+            let current = self.regs.read_allow_cmd_slot(slot);
+            if current != 0 && current & 0xff != u32::from(opcode) {
+                return Err(SpiMonitorError::NoCommandSlot);
+            }
+            slot
+        } else {
+            (FIRST_GENERAL_COMMAND_SLOT..COMMAND_TABLE_SLOTS)
+                .find(|slot| self.regs.read_allow_cmd_slot(*slot) == 0)
+                .ok_or(SpiMonitorError::NoCommandSlot)?
+        };
+        if self.regs.read_allow_cmd_slot(slot) & COMMAND_LOCKED != 0 {
+            return Err(SpiMonitorError::Locked);
+        }
+        self.regs.write_allow_cmd_slot(slot, value);
+        verify_command_slot(&self.regs, slot, value)
+    }
+
+    /// Disable every unlocked entry matching an opcode.
+    pub fn remove_command(&self, opcode: u8) -> Result<usize> {
+        let mut count = 0;
+        for slot in 0..COMMAND_TABLE_SLOTS {
+            let current = self.regs.read_allow_cmd_slot(slot);
+            if current & 0xff == u32::from(opcode) {
+                if current & COMMAND_LOCKED != 0 {
+                    return Err(SpiMonitorError::Locked);
+                }
+                self.regs.write_allow_cmd_slot(slot, 0);
+                verify_command_slot(&self.regs, slot, 0)?;
+                count += 1;
+            }
+        }
+        if count == 0 {
+            return Err(SpiMonitorError::UnsupportedCommand(opcode));
+        }
+        Ok(count)
+    }
+
+    /// Lock every command-table entry matching an opcode.
+    pub fn lock_command(&self, opcode: u8) -> Result<usize> {
+        let mut count = 0;
+        for slot in 0..COMMAND_TABLE_SLOTS {
+            let current = self.regs.read_allow_cmd_slot(slot);
+            if current & 0xff == u32::from(opcode) {
+                let updated = current | COMMAND_LOCKED;
+                self.regs.write_allow_cmd_slot(slot, updated);
+                verify_command_slot(&self.regs, slot, updated)?;
+                count += 1;
+            }
+        }
+        if count == 0 {
+            return Err(SpiMonitorError::UnsupportedCommand(opcode));
+        }
+        Ok(count)
+    }
+
+    /// Update an address privilege region, matching the Zephyr shell
+    /// `addr read/write enable/disable` operations.
+    pub fn configure_region(
+        &self,
+        start: u32,
+        length: u32,
+        direction: PrivilegeDirection,
+        op: PrivilegeOp,
+    ) -> Result<()> {
+        let lock = self.regs.read_lock_status();
+        let locked = match direction {
+            PrivilegeDirection::Read => lock & LOCK_READ_PRIVILEGE != 0,
+            PrivilegeDirection::Write => lock & LOCK_WRITE_PRIVILEGE != 0,
+        };
+        if locked {
+            return Err(SpiMonitorError::Locked);
+        }
+        configure_privilege_region(&self.regs, start, length, direction, op)
+    }
+
+    /// Read one word from the selected privilege bitmap.
+    pub fn privilege_word(&self, direction: PrivilegeDirection, index: usize) -> Result<u32> {
+        if index >= PRIVILEGE_TABLE_WORDS {
+            return Err(SpiMonitorError::InvalidSlot);
+        }
+        select_privilege_table(&self.regs, direction);
+        Ok(self.regs.read_addr_filter_slot(index))
+    }
+
+    /// Lock one privilege bitmap, matching the shell `addr lock read/write`.
+    pub fn lock_privilege_table(&self, direction: PrivilegeDirection) -> Result<()> {
+        let mask = match direction {
+            PrivilegeDirection::Read => LOCK_READ_PRIVILEGE,
+            PrivilegeDirection::Write => LOCK_WRITE_PRIVILEGE,
+        };
+        self.regs.modify_lock_status(|bits| *bits |= mask);
+        if self.regs.read_lock_status() & mask != mask {
+            return Err(SpiMonitorError::LockFailed);
+        }
+        Ok(())
+    }
+
     /// Enable the monitor filter (SPIPF000 bit 0).
     ///
     /// Mirrors Zephyr's `spim_monitor_enable(dev, true)`.
@@ -203,6 +314,9 @@
             PassthroughMode::Enabled => {
                 *bits = (*bits & !CTRL_PASSTHROUGH_MASK) | CTRL_SINGLE_PASSTHROUGH_BIT
             }
+            PassthroughMode::MultiEnabled => {
+                *bits = (*bits & !CTRL_PASSTHROUGH_MASK) | CTRL_MULTI_PASSTHROUGH_BIT
+            }
             PassthroughMode::Disabled => *bits &= !CTRL_PASSTHROUGH_MASK,
         });
     }
@@ -436,6 +550,7 @@
 /// Confirmed from aspeed-rust implementation (src/spimonitor/hardware.rs).
 /// Register field names from ast1060_pac provide safe typed accessors.
 const CTRL_SINGLE_PASSTHROUGH_BIT: u32 = 1 << 0;
+const CTRL_MULTI_PASSTHROUGH_BIT: u32 = 1 << 1;
 const CTRL_PASSTHROUGH_MASK: u32 = (1 << 0) | (1 << 1);
 const CTRL_MONITOR_ENABLE_BIT: u32 = 1 << 2;
 #[allow(dead_code)]
@@ -445,7 +560,6 @@
 const CTRL2_VIOLATION_STATUS_MASK: u32 = 0x7;
 const CTRL2_VIOLATION_IRQ_ENABLE_MASK: u32 = 0x7 << 16;
 const CTRL2_PUSH_PULL: u32 = 1 << 31;
-
 const COMMAND_TABLE_SLOTS: usize = 32;
 const FIRST_GENERAL_COMMAND_SLOT: usize = 2;
 const LAST_GENERAL_COMMAND_SLOT_EXCLUSIVE: usize = 31;
@@ -478,6 +592,17 @@
     regs.modify_ctrl(|bits| *bits = (*bits & 0x00ff_ffff) | selection);
 }
 
+fn verify_command_slot(
+    regs: &SpiMonitorRegisters,
+    slot: usize,
+    expected: u32,
+) -> Result<usize> {
+    if regs.read_allow_cmd_slot(slot) != expected {
+        return Err(SpiMonitorError::VerificationFailed);
+    }
+    Ok(slot)
+}
+
 fn initialize_privilege_table(
     regs: &SpiMonitorRegisters,
     direction: PrivilegeDirection,
diff --git a/target/ast10x0/peripherals/spimonitor/types.rs b/target/ast10x0/peripherals/spimonitor/types.rs
index 3be10bf..5c00cec 100644
--- a/target/ast10x0/peripherals/spimonitor/types.rs
+++ b/target/ast10x0/peripherals/spimonitor/types.rs
@@ -28,7 +28,10 @@
 /// Mirrors Zephyr's `spim_passthrough_config`.
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum PassthroughMode {
+    /// Enable single-bit passthrough.
     Enabled,
+    /// Enable multi-bit passthrough.
+    MultiEnabled,
     Disabled,
 }
 
diff --git a/target/ast10x0/tests/spimonitor/target.rs b/target/ast10x0/tests/spimonitor/target.rs
index f91d6be..3792b23 100644
--- a/target/ast10x0/tests/spimonitor/target.rs
+++ b/target/ast10x0/tests/spimonitor/target.rs
@@ -1,16 +1,24 @@
 // Licensed under the Apache-2.0 license
 // SPDX-License-Identifier: Apache-2.0
 
-//! AST10x0 SPI monitor register and routing smoke test.
+//! AST10x0 SPI monitor configuration hardware test.
 
 #![no_std]
 #![no_main]
 
-use ast10x0_board::apply_spim_pinctrl;
-use ast10x0_peripherals::scu::{ScuRegisters, SpiMonitorInstance};
+use core::cell::UnsafeCell;
+
+use ast10x0_board::{
+    apply_spim_external_mux, apply_spim_pinctrl, spim_external_mux_state,
+};
+use ast10x0_peripherals::scu::{
+    ScuError, ScuExtMuxSelect, ScuRegisters, SpiMonitorInstance, SpiMonitorPassthrough,
+    SpiMonitorSource,
+};
 use ast10x0_peripherals::spimonitor::{
-    command_table_value, ExtMuxSel, MonitorPolicy, MonitorState, PassthroughMode, SpiMonitor,
-    SpiMonitorController, SpiMonitorError, Uninitialized,
+    ConfiguredSpiMonitor, LockState, MonitorPolicy, MonitorState, PassthroughMode,
+    PrivilegeDirection, PrivilegeOp, SpiMonitor, SpiMonitorController, SpiMonitorError,
+    Uninitialized,
 };
 use console_backend::console_backend_write_all;
 use target_common::{declare_target, TargetInterface};
@@ -18,115 +26,237 @@
 
 pub struct Target {}
 
-const CTRL_MONITOR_ENABLE: u32 = 1 << 2;
-const CTRL_SINGLE_BIT_PASSTHROUGH: u32 = 1 << 0;
-const TEST_COMMANDS: [u8; 3] = [0x9f, 0x05, 0x06];
-const FIRST_GENERAL_COMMAND_SLOT: usize = 2;
+const SPIM: SpiMonitorInstance = SpiMonitorInstance::Spim0;
+const PROTECTED_LENGTH: u32 = 0x0010_0000;
+const LOG_RAM_BYTES: usize = 0x200;
+const LOG_RAM_WORDS: usize = LOG_RAM_BYTES / core::mem::size_of::<u32>();
+const COMMAND_VALID_MASK: u32 = (1 << 30) | (1 << 31);
+const COMMAND_LOCKED: u32 = 1 << 23;
+const LOCK_REQUIRED: u32 = (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 30) | (1 << 31);
 
-fn check_register(actual: u32, expected: u32) -> Result<(), SpiMonitorError> {
-    if actual != expected {
-        pw_log::info!(
-            "register mismatch: expected=0x{:08x}, actual=0x{:08x}",
-            expected as u32,
-            actual as u32
-        );
-        return Err(SpiMonitorError::InvalidTransition);
+#[repr(align(16))]
+struct LogRam(UnsafeCell<[u32; LOG_RAM_WORDS]>);
+
+// SAFETY: This test is single-threaded and gives the buffer exclusively to SPIPF.
+unsafe impl Sync for LogRam {}
+
+static LOG_RAM: LogRam = LogRam(UnsafeCell::new([0; LOG_RAM_WORDS]));
+
+#[derive(Clone, Copy)]
+enum TestError {
+    Monitor,
+    Scu,
+    Check,
+}
+
+impl From<SpiMonitorError> for TestError {
+    fn from(_: SpiMonitorError) -> Self {
+        Self::Monitor
     }
+}
+
+impl From<ScuError> for TestError {
+    fn from(_: ScuError) -> Self {
+        Self::Scu
+    }
+}
+
+macro_rules! test_check {
+    ($condition:expr, $message:literal) => {
+        if !$condition {
+            pw_log::info!($message);
+            return Err(TestError::Check);
+        }
+    };
+}
+
+fn log_buffer() -> &'static mut [u32] {
+    // SAFETY: The test is single-threaded and calls this exactly once.
+    unsafe { &mut *LOG_RAM.0.get() }
+}
+
+fn configure_wiring(scu: &ScuRegisters) -> Result<(), TestError> {
+    pw_log::info!("START: external monitor pinctrl, routing, and mux");
+    apply_spim_pinctrl(scu, SPIM);
+    scu.disable_spim_cs_internal_pull_down(SPIM);
+
+    // SPIPF observes external BMC/host traffic. Do not detour SPI1 or SPI2
+    // internally into the monitor.
+    scu.set_spim_internal_mux(SpiMonitorSource::Spi1, 0)?;
+    test_check!(
+        scu.route_control_raw() & 0x0f == 0,
+        "FAIL: internal SPI master detour is enabled"
+    );
+
+    // This SCU bit enables the SPIPF signal path. Controller bypass/filtering
+    // is controlled independently by SPIPF000[1:0].
+    scu.set_spim_passthrough(SPIM, SpiMonitorPassthrough::Enabled);
+    scu.set_spim_miso_multi_func(SPIM, true);
+    scu.set_spim_filter(SPIM, true);
+
+    apply_spim_external_mux(SPIM, ScuExtMuxSelect::Mux0);
+    test_check!(
+        spim_external_mux_state(SPIM) == Some(ScuExtMuxSelect::Mux0),
+        "FAIL: external mux 0 GPIO readback"
+    );
+    apply_spim_external_mux(SPIM, ScuExtMuxSelect::Mux1);
+    test_check!(
+        spim_external_mux_state(SPIM) == Some(ScuExtMuxSelect::Mux1),
+        "FAIL: external mux 1 GPIO readback"
+    );
+    scu.set_spim_ext_mux(SPIM, ScuExtMuxSelect::Mux1);
+
+    test_check!(
+        scu.route_control_raw() & 0x0f == 0,
+        "FAIL: external monitor setup changed internal SPI routing"
+    );
+    pw_log::info!("PASS: external monitor pinctrl, routing, and mux");
     Ok(())
 }
 
-fn run_spimonitor_test() -> Result<(), SpiMonitorError> {
-    pw_log::info!("=== AST10x0 SPI monitor smoke test ===");
-
-    // Match the device-tree pinctrl-0 setup for spim1/SPIPF1.
-    let scu = unsafe { ScuRegisters::new_global_unlocked() };
-    apply_spim_pinctrl(&scu, SpiMonitorInstance::Spim0);
-
-    // This target owns SPIM0/SPIPF1 for its complete lifetime.
-    let monitor = unsafe {
-        SpiMonitor::<Uninitialized>::new(SpiMonitorController::Spim0)
-    };
-    if monitor.state() != MonitorState::Uninitialized {
-        return Err(SpiMonitorError::InvalidTransition);
-    }
-
-    let original_ctrl = monitor.regs().read_ctrl();
-    let original_slots = [
-        monitor.regs().read_allow_cmd_slot(2),
-        monitor.regs().read_allow_cmd_slot(3),
-        monitor.regs().read_allow_cmd_slot(4),
-    ];
-
+fn build_policy() -> MonitorPolicy {
     let mut policy = MonitorPolicy::empty();
-    policy.allow_commands[..TEST_COMMANDS.len()].copy_from_slice(&TEST_COMMANDS);
-    policy.allow_command_count = TEST_COMMANDS.len();
+    policy.allow_commands[..9]
+        .copy_from_slice(&[0x9f, 0x05, 0x06, 0x04, 0x02, 0x12, 0x20, 0x21, 0x0c]);
+    policy.allow_command_count = 9;
+    let _ = policy.add_region(
+        0,
+        PROTECTED_LENGTH,
+        PrivilegeDirection::Write,
+        PrivilegeOp::Disable,
+    );
+    policy
+}
 
-    let configured = monitor.apply_policy(&policy)?;
-    if configured.state() != MonitorState::Configured {
-        return Err(SpiMonitorError::InvalidTransition);
-    }
+fn initialize_monitor() -> Result<ConfiguredSpiMonitor, TestError> {
+    pw_log::info!("START: monitor reset, policy, and log RAM");
+    let monitor = unsafe { SpiMonitor::<Uninitialized>::new(SpiMonitorController::Spim0) };
+    monitor.software_reset();
+    test_check!(
+        monitor.regs().read_ctrl() & (1 << 15) == 0,
+        "FAIL: software reset did not deassert"
+    );
 
-    let original_mux = configured.get_ext_mux();
-    let result = (|| {
-        for (index, command) in TEST_COMMANDS.iter().copied().enumerate() {
-            let expected =
-                command_table_value(command, false).ok_or(SpiMonitorError::UnsupportedCommand(
-                    command,
-                ))?;
-            check_register(
-                configured
-                    .regs()
-                    .read_allow_cmd_slot(FIRST_GENERAL_COMMAND_SLOT + index),
-                expected,
-            )?;
-        }
-        pw_log::info!("command table readback passed");
+    let configured = monitor.apply_policy(&build_policy())?;
+    test_check!(
+        configured.state() == MonitorState::Configured,
+        "FAIL: monitor did not enter configured state"
+    );
 
-        configured.enable();
-        check_register(
-            configured.regs().read_ctrl() & CTRL_MONITOR_ENABLE,
-            CTRL_MONITOR_ENABLE,
-        )?;
+    configured.configure_log(log_buffer())?;
+    test_check!(
+        configured.regs().read_log_capacity_entries() as usize == LOG_RAM_WORDS,
+        "FAIL: 0x200-byte log RAM configuration"
+    );
+    test_check!(
+        configured.regs().read_log_idx_reg() == 0,
+        "FAIL: violation log pointer was not reset"
+    );
 
-        configured.set_passthrough(PassthroughMode::Enabled);
-        check_register(
-            configured.regs().read_ctrl() & CTRL_SINGLE_BIT_PASSTHROUGH,
-            CTRL_SINGLE_BIT_PASSTHROUGH,
-        )?;
+    configured.set_push_pull(true);
+    configured.set_passthrough(PassthroughMode::Disabled);
+    configured.enable();
+    test_check!(
+        configured.regs().read_ctrl() & (1 << 2) != 0,
+        "FAIL: monitor filter is not enabled"
+    );
+    pw_log::info!("PASS: monitor reset, policy, and log RAM");
+    Ok(configured)
+}
 
-        configured.set_passthrough(PassthroughMode::Disabled);
-        check_register(
-            configured.regs().read_ctrl() & CTRL_SINGLE_BIT_PASSTHROUGH,
-            0,
-        )?;
+fn test_passthrough_control(configured: &ConfiguredSpiMonitor) -> Result<(), TestError> {
+    pw_log::info!("START: passthrough control readback");
+    configured.set_passthrough(PassthroughMode::Enabled);
+    test_check!(
+        configured.regs().read_ctrl() & 0x3 == 0x1,
+        "FAIL: single-bit passthrough readback"
+    );
+    configured.set_passthrough(PassthroughMode::MultiEnabled);
+    test_check!(
+        configured.regs().read_ctrl() & 0x3 == 0x2,
+        "FAIL: multi-bit passthrough readback"
+    );
+    configured.set_passthrough(PassthroughMode::Disabled);
+    test_check!(
+        configured.regs().read_ctrl() & 0x3 == 0,
+        "FAIL: passthrough disable readback"
+    );
+    pw_log::info!("PASS: passthrough control readback");
+    Ok(())
+}
 
-        let test_mux = match original_mux {
-            ExtMuxSel::Sel0 => ExtMuxSel::Sel1,
-            ExtMuxSel::Sel1 => ExtMuxSel::Sel0,
-        };
-        configured.set_ext_mux(test_mux);
-        if configured.get_ext_mux() != test_mux {
-            pw_log::info!("external mux readback failed");
-            return Err(SpiMonitorError::InvalidTransition);
-        }
-        pw_log::info!("control and external mux readback passed");
-        Ok(())
-    })();
+fn test_command_policy(configured: &ConfiguredSpiMonitor) -> Result<(), TestError> {
+    pw_log::info!("START: command table add and remove");
+    configured.remove_command(0x05)?;
+    let status_slot = configured.add_command(0x05, false)?;
+    test_check!(
+        configured.regs().read_allow_cmd_slot(status_slot) & COMMAND_VALID_MASK != 0,
+        "FAIL: command add readback"
+    );
+    configured.remove_command(0x05)?;
+    test_check!(
+        configured.regs().read_allow_cmd_slot(status_slot) == 0,
+        "FAIL: command remove did not clear slot"
+    );
+    configured.add_command(0x05, false)?;
+    pw_log::info!("PASS: command table add and remove");
+    Ok(())
+}
 
-    // Restore every register changed by this smoke test.
-    configured.set_ext_mux(original_mux);
-    configured.regs().write_ctrl(original_ctrl);
-    for (index, value) in original_slots.iter().copied().enumerate() {
-        configured
-            .regs()
-            .write_allow_cmd_slot(FIRST_GENERAL_COMMAND_SLOT + index, value);
-    }
+fn test_address_policy(configured: &ConfiguredSpiMonitor) -> Result<(), TestError> {
+    pw_log::info!("START: protected and unprotected address policy");
+    test_check!(
+        configured.privilege_word(PrivilegeDirection::Write, 0)? == 0,
+        "FAIL: protected write region programming"
+    );
+    test_check!(
+        configured.privilege_word(PrivilegeDirection::Write, 2)? == u32::MAX,
+        "FAIL: unprotected write region programming"
+    );
+    pw_log::info!("PASS: protected and unprotected address policy");
+    Ok(())
+}
 
-    result
+fn test_policy_locking(configured: ConfiguredSpiMonitor) -> Result<(), TestError> {
+    pw_log::info!("START: policy locking and readback");
+    configured.lock_command(0x9f)?;
+    let locked = configured.lock()?;
+    test_check!(
+        locked.lock_state() == LockState::Locked,
+        "FAIL: monitor lock state"
+    );
+    test_check!(
+        locked.regs().read_lock_status() & LOCK_REQUIRED == LOCK_REQUIRED,
+        "FAIL: lock register readback"
+    );
+    let slot = locked.regs().read_allow_cmd_slot(2);
+    locked.regs().write_allow_cmd_slot(2, 0);
+    test_check!(
+        locked.regs().read_allow_cmd_slot(2) == slot && slot & COMMAND_LOCKED != 0,
+        "FAIL: command lock did not prevent modification"
+    );
+    pw_log::info!("PASS: policy locking and readback");
+    Ok(())
+}
+
+fn run_spimonitor_test() -> Result<(), TestError> {
+    pw_log::info!("=== AST10x0 external SPI monitor configuration test ===");
+
+    let scu = unsafe { ScuRegisters::new_global_unlocked() };
+    configure_wiring(&scu)?;
+    let configured = initialize_monitor()?;
+    test_passthrough_control(&configured)?;
+    test_command_policy(&configured)?;
+    test_address_policy(&configured)?;
+    test_policy_locking(configured)?;
+
+    pw_log::info!("External traffic blocking requires a BMC/host stimulus");
+    pw_log::info!("=== all SPI monitor configuration tests passed ===");
+    Ok(())
 }
 
 impl TargetInterface for Target {
-    const NAME: &'static str = "AST10x0 SPI Monitor Smoke Test";
+    const NAME: &'static str = "AST10x0 External SPI Monitor Configuration Test";
 
     fn main() -> ! {
         let sentinel = if run_spimonitor_test().is_ok() {