xref: /DragonOS/kernel/src/driver/net/dma.rs (revision c635d8a9cfe25bc11779f323ef0c7d7a0f597d4a)
1 use crate::arch::mm::kernel_page_flags;
2 
3 use crate::arch::MMArch;
4 
5 use crate::mm::kernel_mapper::KernelMapper;
6 use crate::mm::page::{page_manager_lock_irqsave, EntryFlags};
7 use crate::mm::{
8     allocator::page_frame::{
9         allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
10     },
11     MemoryManagementArch, PhysAddr, VirtAddr,
12 };
13 use core::ptr::NonNull;
14 const PAGE_SIZE: usize = 4096;
15 /// @brief 申请用于DMA的内存页
16 /// @param pages 页数(4k一页)
17 /// @return PhysAddr 获得的内存页的初始物理地址
18 pub fn dma_alloc(pages: usize) -> (usize, NonNull<u8>) {
19     let page_num = PageFrameCount::new(
20         ((pages * PAGE_SIZE + MMArch::PAGE_SIZE - 1) / MMArch::PAGE_SIZE).next_power_of_two(),
21     );
22     unsafe {
23         let (paddr, count) = allocate_page_frames(page_num).expect("e1000e: alloc page failed");
24         let virt = MMArch::phys_2_virt(paddr).unwrap();
25         // 清空这块区域,防止出现脏数据
26         core::ptr::write_bytes(virt.data() as *mut u8, 0, count.data() * MMArch::PAGE_SIZE);
27 
28         let dma_flags: EntryFlags<MMArch> = EntryFlags::mmio_flags();
29 
30         let mut kernel_mapper = KernelMapper::lock();
31         let kernel_mapper = kernel_mapper.as_mut().unwrap();
32         let flusher = kernel_mapper
33             .remap(virt, dma_flags)
34             .expect("e1000e: remap failed");
35         flusher.flush();
36         return (
37             paddr.data(),
38             NonNull::new(MMArch::phys_2_virt(paddr).unwrap().data() as _).unwrap(),
39         );
40     }
41 }
42 /// @brief 释放用于DMA的内存页
43 /// @param paddr 起始物理地址 pages 页数(4k一页)
44 /// @return i32 0表示成功
45 pub unsafe fn dma_dealloc(paddr: usize, vaddr: NonNull<u8>, pages: usize) -> i32 {
46     let page_count = PageFrameCount::new(
47         ((pages * PAGE_SIZE + MMArch::PAGE_SIZE - 1) / MMArch::PAGE_SIZE).next_power_of_two(),
48     );
49 
50     // 恢复页面属性
51     let vaddr = VirtAddr::new(vaddr.as_ptr() as usize);
52     let mut kernel_mapper = KernelMapper::lock();
53     let kernel_mapper = kernel_mapper.as_mut().unwrap();
54     let flusher = kernel_mapper
55         .remap(vaddr, kernel_page_flags(vaddr))
56         .expect("e1000e: remap failed");
57     flusher.flush();
58 
59     unsafe {
60         deallocate_page_frames(
61             PhysPageFrame::new(PhysAddr::new(paddr)),
62             page_count,
63             &mut page_manager_lock_irqsave(),
64         );
65     }
66     return 0;
67 }
68