//! Development guest exercise of logical resource claims against live MMIO //! identities and DTB IRQs. The static buffers are never submitted for DMA. use super::*; use turkos_kernel::runtime::device_registry::{DeviceKey, DeviceKind, ResourceError, ResourceKind, ResourceRange, ResourceRegistry, Transport}; #[repr(align(4096))] struct AlignedDma([u8; 4096]); static mut BLOCK_DMA: AlignedDma = AlignedDma([0; 4096]); static mut NETWORK_DMA: AlignedDma = AlignedDma([0; 4096]); pub fn run(boot: &BootData) -> Result<(), &'static str> { 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(|_| "k1410-dtb-devices")?; let mut block = None; let mut network = None; for node in nodes.as_slice() { if unsafe { os_k940_read(node.base, 0) } != turkos_kernel::virtio_mmio::MAGIC { return Err("k1410-magic"); } let id = unsafe { os_k940_read(node.base, 8) }; if id != 1 && id != 2 { continue; } if unsafe { os_k940_read(node.base, 4) } != 2 || node.size != 0x200 { return Err("k1410-version-or-size"); } if id == 2 && block.replace(node.base).is_some() { return Err("k1410-duplicate-block"); } if id == 1 && network.replace(node.base).is_some() { return Err("k1410-duplicate-network"); } } let block = block.ok_or("k1410-no-block")?; let network = network.ok_or("k1410-no-network")?; let scratch = unsafe { &*core::ptr::addr_of!(OS_K700_WORKSPACE) }; let block_irq = turkos_kernel::runtime::platform::os_k940_virtio_spi( blob, scratch, block, boot.interrupts.gic_distributor) .map_err(|_| "k1410-block-spi")?.0; let network_irq = turkos_kernel::runtime::platform::os_k940_virtio_spi( blob, scratch, network, boot.interrupts.gic_distributor) .map_err(|_| "k1410-network-spi")?.0; if block_irq == network_irq { return Err("k1410-same-spi"); } let block_dma = core::ptr::addr_of_mut!(BLOCK_DMA) as u64; let network_dma = core::ptr::addr_of_mut!(NETWORK_DMA) as u64; if block_dma == network_dma { return Err("k1410-same-dma-buffer"); } let block_key = DeviceKey { transport: Transport::Mmio, location: block }; let network_key = DeviceKey { transport: Transport::Mmio, location: network }; let block_ranges = [ ResourceRange { kind: ResourceKind::Mmio, start: block, length: 0x200 }, ResourceRange { kind: ResourceKind::Irq, start: u64::from(block_irq), length: 1 }, ResourceRange { kind: ResourceKind::Dma, start: block_dma, length: 4096 }, ]; let network_ranges = [ ResourceRange { kind: ResourceKind::Mmio, start: network, length: 0x200 }, ResourceRange { kind: ResourceKind::Irq, start: u64::from(network_irq), length: 1 }, ResourceRange { kind: ResourceKind::Dma, start: network_dma, length: 4096 }, ]; let mut registry = ResourceRegistry::<2, 6>::new(); let owner = registry.attach(block_key, DeviceKind::Block, &block_ranges) .map_err(|_| "k1410-block-attach")?; let before = registry.snapshot(); // First two proposed claims are free; the last BAR overlaps block MMIO. // A failed request must publish none of them and consume no device slot. let conflict = [network_ranges[1], network_ranges[2], ResourceRange { kind: ResourceKind::Mmio, start: block + 0x100, length: 0x100 }]; if registry.attach(network_key, DeviceKind::Network, &conflict) != Err(ResourceError::Conflict) || registry.snapshot() != before || registry.get(owner).map_err(|_| "k1410-owner-lost")?.key != block_key { return Err("k1410-conflict-not-atomic"); } let net = registry.attach(network_key, DeviceKind::Network, &network_ranges) .map_err(|_| "k1410-network-attach")?; if registry.device_count() != 2 || registry.claim_count() != 6 || registry.get(net).map_err(|_| "k1410-network")?.key != network_key { return Err("k1410-healthy-after-rejection"); } write_str("TURKOS/OS/K1410-TRACE: BLOCK=0x"); write_hex(block as usize); write_str(" NETWORK=0x"); write_hex(network as usize); write_str(" BLOCK-IRQ=0x"); write_hex(block_irq as usize); write_str(" NETWORK-IRQ=0x"); write_hex(network_irq as usize); write_line(" CONFLICT-REJECTED-SNAPSHOT-EQUAL LIVE=2 CLAIMS=6"); if registry.detach(owner).map_err(|_| "k1410-block-detach")?.key != block_key || registry.detach(net).map_err(|_| "k1410-network-detach")?.key != network_key || registry.device_count() != 0 || registry.claim_count() != 0 { return Err("k1410-cleanup"); } write_line("TURKOS/OS/K1410-TRACE: LOGICAL-CLEANUP LIVE=0 CLAIMS=0"); Ok(()) }