use core::ptr::NonNull;
use core::time::Duration;
use ixgbe_driver::IxgbeHal;
struct TestHal;
static mut DMA_ALLOC_COUNT: usize = 0;
static mut DMA_DEALLOC_COUNT: usize = 0;
unsafe impl IxgbeHal for TestHal {
fn dma_alloc(size: usize) -> (usize, NonNull<u8>) {
unsafe {
DMA_ALLOC_COUNT += 1;
}
let layout = std::alloc::Layout::from_size_align(size, 4096).expect("Invalid layout");
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
panic!("DMA allocation failed in test");
}
let phys_addr = ptr as usize; (phys_addr, NonNull::new(ptr).unwrap())
}
unsafe fn dma_dealloc(paddr: usize, vaddr: NonNull<u8>, size: usize) -> i32 {
unsafe {
DMA_DEALLOC_COUNT += 1;
}
let layout = std::alloc::Layout::from_size_align(size, 4096).expect("Invalid layout");
std::alloc::dealloc(vaddr.as_ptr(), layout);
0 }
unsafe fn mmio_phys_to_virt(paddr: usize, size: usize) -> NonNull<u8> {
NonNull::new(paddr as *mut u8).unwrap()
}
unsafe fn mmio_virt_to_phys(vaddr: NonNull<u8>, size: usize) -> usize {
vaddr.as_ptr() as usize
}
fn wait_until(duration: Duration) -> Result<(), &'static str> {
Ok(())
}
}
#[test]
fn test_dma_memory_lifecycle() {
unsafe {
DMA_ALLOC_COUNT = 0;
DMA_DEALLOC_COUNT = 0;
}
let (phys_addr, virt_ptr) = TestHal::dma_alloc(4096);
unsafe {
assert_eq!(DMA_ALLOC_COUNT, 1);
assert_eq!(DMA_DEALLOC_COUNT, 0);
}
assert!(!virt_ptr.as_ptr().is_null());
assert!(phys_addr != 0);
let result = unsafe { TestHal::dma_dealloc(phys_addr, virt_ptr, 4096) };
assert_eq!(result, 0);
unsafe {
assert_eq!(DMA_ALLOC_COUNT, 1);
assert_eq!(DMA_DEALLOC_COUNT, 1);
}
}
#[test]
fn test_mmio_address_translation() {
let test_paddr = 0xDEADBEEF;
let test_size = 4096;
let virt_ptr = unsafe { TestHal::mmio_phys_to_virt(test_paddr, test_size) };
assert_eq!(virt_ptr.as_ptr() as usize, test_paddr);
let phys_addr = unsafe { TestHal::mmio_virt_to_phys(virt_ptr, test_size) };
assert_eq!(phys_addr, test_paddr);
}
#[test]
fn test_wait_until_functionality() {
let duration = Duration::from_millis(100);
let result = TestHal::wait_until(duration);
assert!(result.is_ok());
}
#[test]
fn test_multiple_dma_allocations() {
unsafe {
DMA_ALLOC_COUNT = 0;
DMA_DEALLOC_COUNT = 0;
}
let mut allocations = Vec::new();
for i in 0..5 {
let size = 4096 * (i + 1);
let (phys_addr, virt_ptr) = TestHal::dma_alloc(size);
allocations.push((phys_addr, virt_ptr, size));
}
unsafe {
assert_eq!(DMA_ALLOC_COUNT, 5);
assert_eq!(DMA_DEALLOC_COUNT, 0);
}
for (phys_addr, virt_ptr, size) in allocations {
let result = unsafe { TestHal::dma_dealloc(phys_addr, virt_ptr, size) };
assert_eq!(result, 0);
}
unsafe {
assert_eq!(DMA_ALLOC_COUNT, 5);
assert_eq!(DMA_DEALLOC_COUNT, 5);
}
}
#[test]
fn test_hal_trait_object_safety() {
struct HalWrapper<T: IxgbeHal>(core::marker::PhantomData<T>);
impl<T: IxgbeHal> HalWrapper<T> {
fn test_allocation(&self) -> usize {
let (phys_addr, _virt_ptr) = T::dma_alloc(4096);
phys_addr
}
}
let wrapper = HalWrapper::<TestHal>(core::marker::PhantomData);
let addr = wrapper.test_allocation();
assert!(addr != 0);
}
#[test]
fn test_error_handling_in_hal() {
let result = TestHal::wait_until(Duration::from_secs(1));
assert!(result.is_ok());
}
struct FailingHal;
unsafe impl IxgbeHal for FailingHal {
fn dma_alloc(_size: usize) -> (usize, NonNull<u8>) {
panic!("DMA allocation failed");
}
unsafe fn dma_dealloc(_paddr: usize, _vaddr: NonNull<u8>, _size: usize) -> i32 {
-1 }
unsafe fn mmio_phys_to_virt(_paddr: usize, _size: usize) -> NonNull<u8> {
panic!("MMIO mapping failed");
}
unsafe fn mmio_virt_to_phys(_vaddr: NonNull<u8>, _size: usize) -> usize {
panic!("Address translation failed");
}
fn wait_until(_duration: Duration) -> Result<(), &'static str> {
Err("Wait timeout")
}
}
#[test]
fn test_failing_hal_error_handling() {
let result = FailingHal::wait_until(Duration::from_secs(1));
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Wait timeout");
}
#[test]
#[should_panic(expected = "DMA allocation failed")]
fn test_failing_hal_allocation() {
let _ = FailingHal::dma_alloc(4096);
}