1 //! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能 2 //! 3 //! 映射关系为: 4 //! 5 //! 虚拟地址 0-100M与虚拟地址 0x8000_0000_0000 - 0x8000_0640_0000 之间具有重映射关系。 6 //! 也就是说,他们的第二级页表在最顶级页表中,占用了第0和第256个页表项。 7 //! 8 //! 对于x86: 9 //! 这里假设在内核引导文件中,已经填写了前100M的页表,其中,前50M是真实映射到内存的,后面的仅仅创建了页表,表项全部为0。 10 11 use bitmap::{traits::BitMapOps, StaticBitmap}; 12 13 use crate::{ 14 libs::spinlock::SpinLock, 15 mm::{MMArch, MemoryManagementArch, PhysAddr}, 16 }; 17 18 use core::marker::PhantomData; 19 20 use super::{ 21 allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage}, 22 page::PageFlags, 23 PageTableKind, VirtAddr, 24 }; 25 26 /// 用于存储重映射页表的位图和页面 27 pub static EARLY_IOREMAP_PAGES: SpinLock<EarlyIoRemapPages> = 28 SpinLock::new(EarlyIoRemapPages::new()); 29 30 /// 早期重映射使用的页表 31 #[repr(C)] 32 #[repr(align(4096))] 33 #[derive(Clone, Copy)] 34 struct EarlyRemapPage { 35 data: [u64; MMArch::PAGE_SIZE], 36 } 37 38 impl EarlyRemapPage { 39 /// 清空数据 40 fn zero(&mut self) { 41 self.data.fill(0); 42 } 43 } 44 45 #[repr(C)] 46 pub struct EarlyIoRemapPages { 47 pages: [EarlyRemapPage; Self::EARLY_REMAP_PAGES_NUM], 48 bmp: StaticBitmap<{ Self::EARLY_REMAP_PAGES_NUM }>, 49 } 50 51 impl EarlyIoRemapPages { 52 /// 预留的用于在内存管理初始化之前,映射内存所使用的页表数量 53 pub const EARLY_REMAP_PAGES_NUM: usize = 256; 54 pub const fn new() -> Self { 55 Self { 56 pages: [EarlyRemapPage { 57 data: [0; MMArch::PAGE_SIZE], 58 }; Self::EARLY_REMAP_PAGES_NUM], 59 bmp: StaticBitmap::new(), 60 } 61 } 62 63 /// 分配一个页面 64 /// 65 /// 如果成功,返回虚拟地址 66 /// 67 /// 如果失败,返回None 68 pub fn allocate_page(&mut self) -> Option<VirtAddr> { 69 if let Some(index) = self.bmp.first_false_index() { 70 self.bmp.set(index, true); 71 // 清空数据 72 self.pages[index].zero(); 73 74 let p = &self.pages[index] as *const EarlyRemapPage as usize; 75 let vaddr = VirtAddr::new(p); 76 assert!(vaddr.check_aligned(MMArch::PAGE_SIZE)); 77 return Some(vaddr); 78 } else { 79 return None; 80 } 81 } 82 83 pub fn free_page(&mut self, addr: VirtAddr) { 84 // 判断地址是否合法 85 let start_vaddr = &self.pages[0] as *const EarlyRemapPage as usize; 86 let offset = addr.data() - start_vaddr; 87 let index = offset / MMArch::PAGE_SIZE; 88 if index < Self::EARLY_REMAP_PAGES_NUM { 89 assert_eq!(self.bmp.get(index).unwrap(), true); 90 self.bmp.set(index, false); 91 } 92 } 93 } 94 95 /// 伪分配器 96 struct PseudoAllocator<MMA> { 97 phantom: PhantomData<MMA>, 98 } 99 100 impl<MMA: MemoryManagementArch> PseudoAllocator<MMA> { 101 pub const fn new() -> Self { 102 Self { 103 phantom: PhantomData, 104 } 105 } 106 } 107 108 /// 为NoInitAllocator实现FrameAllocator 109 impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> { 110 unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> { 111 assert!(count.data() == 1); 112 let vaddr = EARLY_IOREMAP_PAGES.lock_irqsave().allocate_page()?; 113 let paddr = MMA::virt_2_phys(vaddr)?; 114 kdebug!("allocate page: vaddr={:?}, paddr={:?}", vaddr, paddr); 115 return Some((paddr, count)); 116 } 117 118 unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount) { 119 assert_eq!(count.data(), 1); 120 assert!(address.check_aligned(MMA::PAGE_SIZE)); 121 kdebug!("free page: paddr={:?}", address); 122 let vaddr = MMA::phys_2_virt(address); 123 if let Some(vaddr) = vaddr { 124 EARLY_IOREMAP_PAGES.lock_irqsave().free_page(vaddr); 125 } 126 } 127 /// @brief: 获取内存区域页帧的使用情况 128 /// @param self 129 /// @return 页帧的使用情况 130 unsafe fn usage(&self) -> PageFrameUsage { 131 // 暂时不支持 132 panic!("NoInitAllocator can't get page frame usage"); 133 } 134 } 135 136 /// Use pseudo mapper to map physical memory to virtual memory. 137 /// 138 /// ## Safety 139 /// 140 /// 调用该函数时,必须保证内存管理器尚未初始化。否则将导致未定义的行为 141 /// 142 /// 并且,内核引导文件必须以4K页为粒度,填写了前100M的内存映射关系。(具体以本文件开头的注释为准) 143 #[inline(never)] 144 pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) { 145 let flags: PageFlags<MMArch> = PageFlags::new().set_write(true).set_execute(true); 146 147 pseudo_map_phys_with_flags(vaddr, paddr, count, flags); 148 } 149 150 /// Use pseudo mapper to map physical memory to virtual memory 151 /// with READ_ONLY and EXECUTE flags. 152 #[inline(never)] 153 pub unsafe fn pseudo_map_phys_ro(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) { 154 let flags: PageFlags<MMArch> = PageFlags::new().set_write(false).set_execute(true); 155 156 pseudo_map_phys_with_flags(vaddr, paddr, count, flags); 157 } 158 159 #[inline(never)] 160 pub unsafe fn pseudo_map_phys_with_flags( 161 vaddr: VirtAddr, 162 paddr: PhysAddr, 163 count: PageFrameCount, 164 flags: PageFlags<MMArch>, 165 ) { 166 assert!(vaddr.check_aligned(MMArch::PAGE_SIZE)); 167 assert!(paddr.check_aligned(MMArch::PAGE_SIZE)); 168 169 let mut pseudo_allocator = PseudoAllocator::<MMArch>::new(); 170 171 let mut mapper = crate::mm::page::PageMapper::<MMArch, _>::new( 172 PageTableKind::Kernel, 173 MMArch::table(PageTableKind::Kernel), 174 &mut pseudo_allocator, 175 ); 176 177 for i in 0..count.data() { 178 let vaddr = vaddr + i * MMArch::PAGE_SIZE; 179 let paddr = paddr + i * MMArch::PAGE_SIZE; 180 let flusher: crate::mm::page::PageFlush<MMArch> = 181 mapper.map_phys(vaddr, paddr, flags).unwrap(); 182 flusher.ignore(); 183 } 184 185 mapper.make_current(); 186 } 187 188 /// Unmap physical memory from virtual memory. 189 /// 190 /// ## 说明 191 /// 192 /// 该函数在系统启动早期,内存管理尚未初始化的时候使用 193 #[inline(never)] 194 pub unsafe fn pseudo_unmap_phys(vaddr: VirtAddr, count: PageFrameCount) { 195 assert!(vaddr.check_aligned(MMArch::PAGE_SIZE)); 196 assert!(count.data() == 1); 197 198 let mut pseudo_allocator = PseudoAllocator::<MMArch>::new(); 199 200 let mut mapper = crate::mm::page::PageMapper::<MMArch, _>::new( 201 PageTableKind::Kernel, 202 MMArch::table(PageTableKind::Kernel), 203 &mut pseudo_allocator, 204 ); 205 206 for i in 0..count.data() { 207 let vaddr = vaddr + i * MMArch::PAGE_SIZE; 208 mapper.unmap_phys(vaddr, true).map(|(_, _, flusher)| { 209 flusher.ignore(); 210 }); 211 } 212 213 mapper.make_current(); 214 } 215