//! K323: real Device-mapped virtio MMIO MagicValue reads after FDT validation. //! The standard VM has PCI virtio-blk; all 32 MMIO transport bridges still //! expose magic, whether or not a device is attached behind them. use super::*; use turkos_kernel::virtio_mmio; pub fn smoke_test(boot: &BootData) -> ! { let mut valid = 0usize; for node in boot.virtio_mmio.as_slice() { // SAFETY: K322 validates the 0x200 slot inside the four-page MMIO // aperture; the pre-TTBR map_device_window call installed Device // descriptors for all four pages, and this is a 32-bit aligned read. let magic = unsafe { core::ptr::read_volatile(node.base as *const u32) }; if virtio_mmio::validate_magic(magic).is_err() { write_str("TURKOS/VIRTIO-MAGIC-ERROR: BASE=0x"); write_hex(node.base as usize); write_str(" VALUE=0x"); write_hex(magic as usize); write_str("\r\n"); park(); } valid += 1; } if valid != 32 { write_line("TURKOS/VIRTIO-MAGIC-ERROR: transport count"); park(); } write_str("TURKOS/VIRTIO-MAGIC: VALID=0x"); write_hex(valid); write_str(" VALUE=0x"); write_hex(virtio_mmio::MAGIC as usize); write_str("\r\n"); write_line("TURKOS/VIRTIO-MAGIC: PASS"); let mut versions = 0usize; for node in boot.virtio_mmio.as_slice() { // SAFETY: offset +0x004 stays inside the K322-validated Device slot. let version = unsafe { core::ptr::read_volatile((node.base + 4) as *const u32) }; if virtio_mmio::validate_version(version).is_err() { write_str("TURKOS/VIRTIO-VERSION-ERROR: BASE=0x"); write_hex(node.base as usize); write_str(" VALUE=0x"); write_hex(version as usize); write_str("\r\n"); park(); } versions += 1; } if versions != 32 { write_line("TURKOS/VIRTIO-VERSION-ERROR: transport count"); park(); } write_str("TURKOS/VIRTIO-VERSION: VALID=0x"); write_hex(versions); write_str(" VALUE=0x"); write_hex(1); write_str("\r\n"); write_line("TURKOS/VIRTIO-VERSION: PASS"); let mut empty = 0usize; let mut block = 0usize; let mut other = 0usize; let mut other_id = 0u32; let mut selected = 0u64; for node in boot.virtio_mmio.as_slice() { // SAFETY: offset +0x008 stays inside the K322-validated Device slot. let id = unsafe { core::ptr::read_volatile((node.base + 8) as *const u32) }; match virtio_mmio::require_block_device(id) { Ok(()) => { block += 1; selected = node.base; } Err(virtio_mmio::Error::MissingDevice) => empty += 1, Err(virtio_mmio::Error::WrongDevice) => { other += 1; other_id = id; } Err(_) => { write_line("TURKOS/VIRTIO-DEVICE-ERROR: unexpected classification"); park(); } } } if empty + block + other != 32 || block > 1 || other > 1 { write_line("TURKOS/VIRTIO-DEVICE-ERROR: count or ambiguous block"); park(); } write_str("TURKOS/VIRTIO-DEVICE: EMPTY=0x"); write_hex(empty); write_str(" BLOCK=0x"); write_hex(block); write_str(" OTHER=0x"); write_hex(other); write_str(" SELECT=0x"); write_hex(selected as usize); write_str(" OTHER-ID=0x"); write_hex(other_id as usize); write_str("\r\n"); write_line("TURKOS/VIRTIO-DEVICE: PASS"); let mut vendors = 0usize; for node in boot.virtio_mmio.as_slice() { // SAFETY: offset +0x00c stays inside the K322-validated Device slot. let vendor = unsafe { core::ptr::read_volatile((node.base + 12) as *const u32) }; if virtio_mmio::validate_fixture_vendor(vendor).is_err() { write_str("TURKOS/VIRTIO-VENDOR-ERROR: BASE=0x"); write_hex(node.base as usize); write_str(" VALUE=0x"); write_hex(vendor as usize); write_str("\r\n"); park(); } vendors += 1; } if vendors != 32 { write_line("TURKOS/VIRTIO-VENDOR-ERROR: transport count"); park(); } write_str("TURKOS/VIRTIO-VENDOR: VALID=0x"); write_hex(vendors); write_str(" VALUE=0x"); write_hex(virtio_mmio::QEMU_VENDOR as usize); write_str("\r\n"); write_line("TURKOS/VIRTIO-VENDOR: PASS"); let mut offered = 0u32; let mut accepted = 0u32; if block == 1 { // SAFETY: selected is the sole K325-validated block MMIO slot. Legacy // v1 HostFeaturesSel selects the low 32-bit word at +0x010. unsafe { core::ptr::write_volatile((selected + 0x14) as *mut u32, 0); offered = core::ptr::read_volatile((selected + 0x10) as *const u32); } accepted = virtio_mmio::select_read_only_features(offered); if accepted != virtio_mmio::BLK_F_RO { write_line("TURKOS/VIRTIO-FEATURE-ERROR: read-only fixture bit absent"); park(); } } write_str("TURKOS/VIRTIO-FEATURE: BLOCK=0x"); write_hex(block); write_str(" OFFERED=0x"); write_hex(offered as usize); write_str(" ACCEPTED=0x"); write_hex(accepted as usize); write_str("\r\n"); write_line("TURKOS/VIRTIO-FEATURE: PASS"); park() }