1use crate::arch::mm::{paddr_to_vaddr, vaddr_to_paddr};
4use crate::mm::address::{ConvertablePaddr, PageNum, UsizeConvert};
5use crate::mm::frame_allocator::FrameRangeTracker;
6use crate::sync::SpinLock;
7use alloc::collections::btree_map::BTreeMap;
8use core::ptr::NonNull;
9use lazy_static::lazy_static;
10use virtio_drivers::{BufferDirection, Hal, PhysAddr};
11
12lazy_static! {
14 static ref DMA_ALLOCATIONS: SpinLock<BTreeMap<PhysAddr, FrameRangeTracker>> =
15 SpinLock::new(BTreeMap::new());
16}
17
18pub struct VirtIOHal;
20
21unsafe impl Hal for VirtIOHal {
22 fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
24 let frame_range = match crate::mm::frame_allocator::alloc_contig_frames(pages) {
26 Some(range) => range,
27 None => {
28 return (PhysAddr::from(0u64), NonNull::dangling());
30 }
31 };
32
33 let start_ppn = frame_range.start_ppn();
35
36 let phys_addr = PhysAddr::from(start_ppn.start_addr().as_usize() as u64);
38
39 let virt_addr = unsafe { start_ppn.start_addr().to_vaddr().as_mut_ptr::<u8>() };
41 let virt_ptr = NonNull::new(virt_addr).unwrap();
42
43 unsafe {
45 for page_idx in 0..pages {
46 let page_start = virt_addr.add(page_idx * crate::config::PAGE_SIZE);
47
48 for offset in 0..crate::config::PAGE_SIZE {
50 core::ptr::write_volatile(page_start.add(offset), 0);
51 }
52 }
53 }
54
55 DMA_ALLOCATIONS.lock().insert(phys_addr, frame_range);
57
58 (phys_addr, virt_ptr)
59 }
60
61 unsafe fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull<u8>, _pages: usize) -> i32 {
63 let frame_range = DMA_ALLOCATIONS.lock().remove(&paddr);
68 if frame_range.is_some() {
72 0 } else {
74 -1 }
76 }
77
78 unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull<u8> {
80 let phys_addr = paddr as usize;
82 let virt = paddr_to_vaddr(phys_addr);
83
84 let ptr = NonNull::new(virt as *mut u8).expect("mmio_phys_to_virt returned null pointer");
86 ptr
87 }
88
89 unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr {
91 let vaddr = buffer.as_ptr() as *const u8 as usize;
92 let paddr = unsafe { vaddr_to_paddr(vaddr) };
93
94 let result = PhysAddr::from(paddr as u64);
95 result
96 }
97
98 unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {
100 }
102}
103
104impl VirtIOHal {
105 pub fn new() -> Self {
107 Self
108 }
109}