#[path = "../../../os-virtio-pci-common/src/lib.rs"] mod virtio_pci_common; use virtio_pci_common::{decode_common, Error, Function, MemoryBar, Phase, Region, Registry}; fn capability(offset: u32, length: u32, cap_len: u8) -> [u8; 20] { let mut bytes = [0u8; 20]; bytes[0] = 0x09; bytes[2] = cap_len; bytes[3] = 1; bytes[4] = 2; bytes[8..12].copy_from_slice(&offset.to_le_bytes()); bytes[12..16].copy_from_slice(&length.to_le_bytes()); bytes } fn bar() -> MemoryBar { MemoryBar {index: 2, base: 0x1000_0000, size: 0x1000} } fn function(number: u8) -> Function { Function::new(0, 0, number, 0).unwrap() } #[test] fn os_virtio_pci_common_positive() { let region = decode_common(&capability(0x100, 0x100, 20), bar()).unwrap(); assert_eq!(region, Region {base: 0x1000_0100, advertised_length: 0x100}); assert_eq!(region.mapped_end(), 0x1000_0138); let mut registry = Registry::<2>::new(); let claim = registry.claim(function(1), region).unwrap(); assert_eq!(registry.phase(claim), Ok(Phase::Unproven)); registry.observe_reset(claim, 0, 0).unwrap(); registry.mark_active(claim, 0x0f, 1).unwrap(); assert_eq!(registry.phase(claim), Ok(Phase::Active)); registry.observe_reset(claim, 0, 0).unwrap(); registry.release(claim).unwrap(); assert_eq!(registry.count(), 0); let next = registry.claim(function(1), region).unwrap(); assert!(next.generation > claim.generation); assert_eq!(registry.phase(claim), Err(Error::StaleClaim)); registry.observe_reset(next, 0, 0).unwrap(); registry.release(next).unwrap(); } #[test] fn os_virtio_pci_common_negative() { assert_eq!(Function::new(0, 0, 32, 0), Err(Error::InvalidCapability)); assert_eq!(decode_common(&capability(0, 0x38, 16), bar()).unwrap().mapped_end(), 0x1000_0038); let mut bad = capability(0, 0x38, 16); bad[0] = 0x05; assert_eq!(decode_common(&bad, bar()), Err(Error::InvalidCapability)); bad = capability(0, 0x38, 16); bad[3] = 2; assert_eq!(decode_common(&bad, bar()), Err(Error::InvalidCapability)); bad = capability(0, 0x38, 16); bad[4] = 6; assert_eq!(decode_common(&bad, bar()), Err(Error::UnsupportedBar)); assert_eq!(decode_common(&capability(1, 0x38, 16), bar()), Err(Error::InvalidRegion)); assert_eq!(decode_common(&capability(0, 0x37, 16), bar()), Err(Error::InvalidRegion)); assert_eq!(decode_common(&capability(0xff0, 0x38, 16), bar()), Err(Error::InvalidRegion)); assert_eq!(decode_common(&capability(0, 0x38, 16), MemoryBar {base: u64::MAX - 0xfff, ..bar()}), Err(Error::InvalidBar)); let region = decode_common(&capability(0x100, 0x38, 16), bar()).unwrap(); let mut registry = Registry::<2>::new(); let claim = registry.claim(function(1), region).unwrap(); let initial = registry.snapshot(); assert_eq!(registry.claim(function(1), region), Err(Error::DuplicateFunction)); assert_eq!(registry.claim(function(2), Region {base: region.base + 4, advertised_length: 0x38}), Err(Error::Overlap)); assert_eq!(registry.snapshot(), initial); assert_eq!(registry.release(claim), Err(Error::StillActive)); assert_eq!(registry.mark_active(claim, 0x0f, 1), Err(Error::WrongPhase)); assert_eq!(registry.observe_reset(claim, 0, 1), Err(Error::StillActive)); assert_eq!(registry.snapshot(), initial); registry.observe_reset(claim, 0, 0).unwrap(); let reset = registry.snapshot(); assert_eq!(registry.mark_active(claim, 0x03, 1), Err(Error::WrongPhase)); assert_eq!(registry.mark_active(claim, 0x0f, 0), Err(Error::WrongPhase)); assert_eq!(registry.snapshot(), reset); registry.mark_active(claim, 0x0f, 1).unwrap(); assert_eq!(registry.release(claim), Err(Error::StillActive)); registry.observe_reset(claim, 0, 0).unwrap(); registry.release(claim).unwrap(); }