diff --git a/kernel/src/objects/untyped.rs b/kernel/src/objects/untyped.rs index 89d7ef0..ae32717 100644 --- a/kernel/src/objects/untyped.rs +++ b/kernel/src/objects/untyped.rs @@ -130,3 +130,100 @@ impl UntypedCap<'_> { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{arch::vspace::KERNEL_ALLOCATOR, objects::cap::CapEntry}; + use core::alloc::Layout; + use log::info; + + fn alloc_mem(size: usize) -> PhysAddr { + assert!(size.is_power_of_two()); + let layout = Layout::from_size_align(size, 1).unwrap(); + KERNEL_ALLOCATOR.lock().alloc(layout).unwrap() + } + + fn create_untyped_cte(size: usize, is_device: bool) -> CapEntry { + let ptr = alloc_mem(size); + let raw = UntypedCap::mint(0, size.ilog2() as usize, is_device, ptr); + CapEntry::new(raw) + } + + fn create_cnode_cte(size: usize, guard_size: usize, guard: usize) -> CapEntry { + let ptr = alloc_mem(size); + let radix = size.ilog2() as usize - ObjectType::CNode.bits(0); + let raw = CNodeCap::mint(radix, guard_size, guard, ptr); + CapEntry::new(raw) + } + + #[test_case] + fn test_untyped_retype_cnode() { + // create untyped + let untyped_cte = create_untyped_cte(4 * ObjectType::CNode.size(2), false); // 4 cnode (4 entries each) + let mut untyped = UntypedCap::try_from(&untyped_cte).unwrap(); + + // create root cnode + let cnode_cte = create_cnode_cte(ObjectType::CNode.size(4), 3, 0b110); // 1 cnode (16 entries) + let mut cnode = CNodeCap::try_from(&cnode_cte).unwrap(); + + // slots + let slots = cnode.as_object_mut(); + + // retype untyped to cnode + info!("Retyping to ObjectType::CNode"); + untyped.retype(ObjectType::CNode, 2, &mut slots[1..2]).unwrap(); + untyped.retype(ObjectType::CNode, 2, &mut slots[9..12]).unwrap(); + + // check untyped + info!("Checking remain space in untyped"); + assert_eq!(untyped.free_offset(), untyped.block_size()); + assert!(untyped.retype(ObjectType::CNode, 1, &mut slots[0..1]).is_err()); + + // check cnode + info!("Checking retyped cnode length"); + for addr in [1, 9, 10, 11] { + let cte = cnode.resolve_address_bits(0b110_0000 | addr, 7).unwrap(); + let cap = CNodeCap::try_from(cte).unwrap(); + let len = cap.as_object().len(); + assert_eq!(len, 4); + } + info!("Make sure other cnodes are not modified"); + for addr in 0..16 { + if [1, 9, 10, 11].contains(&addr) { + continue; + } + let cte = cnode.resolve_address_bits(0b110_0000 | addr, 7).unwrap(); + NullCap::try_from(cte).unwrap(); + } + } + + #[test_case] + fn test_untyped_retype_device_err() { + // create untyped + let untyped_cte = create_untyped_cte(ObjectType::CNode.size(1), true); + let mut untyped = UntypedCap::try_from(&untyped_cte).unwrap(); + + // create root cnode + let cnode_cte = create_cnode_cte(ObjectType::CNode.size(1), 3, 0b110); + let mut cnode = CNodeCap::try_from(&cnode_cte).unwrap(); + + // slots + let slots = cnode.as_object_mut(); + + // allocate fail + info!("Retyping to ObjectType::CNode with device memory"); + untyped + .retype(ObjectType::CNode, 1, &mut slots[0..1]) + .is_err() + .then_ok((), ()) + .unwrap(); + + // nothing should be changed + info!("Make sure nothing is changed"); + assert_eq!(untyped.free_offset(), 0); + NullCap::try_from(&slots[0]).unwrap(); + } + + // TODO: more tests +}