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 获得的内存页的初始物理地址
dma_alloc(pages: usize) -> (usize, NonNull<u8>)18 pub fn dma_alloc(pages: usize) -> (usize, NonNull<u8>) {
19 let page_num = PageFrameCount::new(
20 (pages * PAGE_SIZE)
21 .div_ceil(MMArch::PAGE_SIZE)
22 .next_power_of_two(),
23 );
24 unsafe {
25 let (paddr, count) = allocate_page_frames(page_num).expect("e1000e: alloc page failed");
26 let virt = MMArch::phys_2_virt(paddr).unwrap();
27 // 清空这块区域,防止出现脏数据
28 core::ptr::write_bytes(virt.data() as *mut u8, 0, count.data() * MMArch::PAGE_SIZE);
29
30 let dma_flags: EntryFlags<MMArch> = EntryFlags::mmio_flags();
31
32 let mut kernel_mapper = KernelMapper::lock();
33 let kernel_mapper = kernel_mapper.as_mut().unwrap();
34 let flusher = kernel_mapper
35 .remap(virt, dma_flags)
36 .expect("e1000e: remap failed");
37 flusher.flush();
38 return (
39 paddr.data(),
40 NonNull::new(MMArch::phys_2_virt(paddr).unwrap().data() as _).unwrap(),
41 );
42 }
43 }
44 /// @brief 释放用于DMA的内存页
45 /// @param paddr 起始物理地址 pages 页数(4k一页)
46 /// @return i32 0表示成功
dma_dealloc(paddr: usize, vaddr: NonNull<u8>, pages: usize) -> i3247 pub unsafe fn dma_dealloc(paddr: usize, vaddr: NonNull<u8>, pages: usize) -> i32 {
48 let page_count = PageFrameCount::new(
49 (pages * PAGE_SIZE)
50 .div_ceil(MMArch::PAGE_SIZE)
51 .next_power_of_two(),
52 );
53
54 // 恢复页面属性
55 let vaddr = VirtAddr::new(vaddr.as_ptr() as usize);
56 let mut kernel_mapper = KernelMapper::lock();
57 let kernel_mapper = kernel_mapper.as_mut().unwrap();
58 let flusher = kernel_mapper
59 .remap(vaddr, kernel_page_flags(vaddr))
60 .expect("e1000e: remap failed");
61 flusher.flush();
62
63 unsafe {
64 deallocate_page_frames(
65 PhysPageFrame::new(PhysAddr::new(paddr)),
66 page_count,
67 &mut page_manager_lock_irqsave(),
68 );
69 }
70 return 0;
71 }
72