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