//! K1405 development guest probe: identity comes from live QEMU MMIO DeviceID. //! Detach below is logical registry detach, not a QEMU hot-unplug operation. use super::*; use turkos_kernel::runtime::device_registry::{DeviceKey, DeviceKind, Error, Registry, Transport}; pub fn run(boot: &BootData) -> Result<(), &'static str> { let mut block = None; let mut network = None; let blob = unsafe { core::slice::from_raw_parts(boot.dtb_address as *const u8, boot.dtb_size) }; let nodes = dtb::discover_virtio_mmio(blob).map_err(|_| "k1405-dtb-devices")?; for node in nodes.as_slice() { let magic = unsafe { os_k940_read(node.base, 0) }; if magic != turkos_kernel::virtio_mmio::MAGIC { return Err("k1405-magic"); } let id = unsafe { os_k940_read(node.base, 8) }; if id != 1 && id != 2 { continue; } let version = unsafe { os_k940_read(node.base, 4) }; if version != 2 { return Err("k1405-version"); } if id == 2 && block.replace(node.base).is_some() { return Err("k1405-duplicate-block"); } if id == 1 && network.replace(node.base).is_some() { return Err("k1405-duplicate-network"); } } let block = block.ok_or("k1405-no-block")?; let network = network.ok_or("k1405-no-network")?; let block_key = DeviceKey { transport: Transport::Mmio, location: block }; let network_key = DeviceKey { transport: Transport::Mmio, location: network }; let mut registry = Registry::<2>::new(); let old = registry.attach(block_key, DeviceKind::Block).map_err(|_| "k1405-attach-block")?; let net = registry.attach(network_key, DeviceKind::Network).map_err(|_| "k1405-attach-network")?; if registry.live_count() != 2 || registry.get(net).map_err(|_| "k1405-net")?.key != network_key { return Err("k1405-pair"); } let before_duplicate = registry.snapshot(); if registry.attach(block_key, DeviceKind::Network) != Err(Error::AlreadyAttached) || registry.snapshot() != before_duplicate { return Err("k1405-duplicate-not-atomic"); } if registry.detach(old).map_err(|_| "k1405-detach")?.key != block_key { return Err("k1405-detach-key"); } let fresh = registry.attach(block_key, DeviceKind::Block).map_err(|_| "k1405-reattach")?; let before_stale = registry.snapshot(); if fresh.slot() != old.slot() || fresh.generation() != old.generation() + 1 || registry.get(old) != Err(Error::StaleHandle) || registry.detach(old) != Err(Error::StaleHandle) || registry.snapshot() != before_stale || registry.get(fresh).map_err(|_| "k1405-fresh")?.key != block_key || registry.get(net).map_err(|_| "k1405-net-after")?.key != network_key || registry.live_count() != 2 { return Err("k1405-stale-revived"); } write_str("TURKOS/OS/K1405-TRACE: BLOCK=0x"); write_hex(block as usize); write_str(" NETWORK=0x"); write_hex(network as usize); write_str(" OLD-GEN=0x"); write_hex(old.generation() as usize); write_str(" NEW-GEN=0x"); write_hex(fresh.generation() as usize); write_line(" STALE-REJECTED LIVE=2"); if registry.detach(fresh).map_err(|_| "k1405-clean-block")?.key != block_key || registry.detach(net).map_err(|_| "k1405-clean-net")?.key != network_key || registry.live_count() != 0 { return Err("k1405-cleanup"); } write_line("TURKOS/OS/K1405-TRACE: LOGICAL-CLEANUP LIVE=0"); Ok(()) }