1 use super::{page::PageFlags, PageTableKind, PhysAddr, VirtAddr}; 2 use crate::{ 3 arch::{ 4 asm::irqflags::{local_irq_restore, local_irq_save}, 5 mm::{LockedFrameAllocator, PageMapper}, 6 }, 7 libs::align::page_align_up, 8 mm::allocator::page_frame::PageFrameCount, 9 mm::{MMArch, MemoryManagementArch}, 10 smp::core::smp_get_processor_id, 11 syscall::SystemError, 12 }; 13 use core::{ 14 ops::Deref, 15 sync::atomic::{compiler_fence, AtomicUsize, Ordering}, 16 }; 17 18 /// 标志当前没有处理器持有内核映射器的锁 19 /// 之所以需要这个标志,是因为AtomicUsize::new(0)会把0当作一个处理器的id 20 const KERNEL_MAPPER_NO_PROCESSOR: usize = !0; 21 /// 当前持有内核映射器锁的处理器 22 static KERNEL_MAPPER_LOCK_OWNER: AtomicUsize = AtomicUsize::new(KERNEL_MAPPER_NO_PROCESSOR); 23 /// 内核映射器的锁计数器 24 static KERNEL_MAPPER_LOCK_COUNT: AtomicUsize = AtomicUsize::new(0); 25 26 pub struct KernelMapper { 27 /// 内核空间映射器 28 mapper: PageMapper, 29 /// 标记当前映射器是否为只读 30 readonly: bool, 31 } 32 33 impl KernelMapper { 34 fn lock_cpu(cpuid: usize, mapper: PageMapper) -> Self { 35 loop { 36 match KERNEL_MAPPER_LOCK_OWNER.compare_exchange_weak( 37 KERNEL_MAPPER_NO_PROCESSOR, 38 cpuid, 39 Ordering::Acquire, 40 Ordering::Relaxed, 41 ) { 42 Ok(_) => break, 43 // 当前处理器已经持有了锁 44 Err(id) if id == cpuid => break, 45 // either CAS failed, or some other hardware thread holds the lock 46 Err(_) => core::hint::spin_loop(), 47 } 48 } 49 50 let prev_count = KERNEL_MAPPER_LOCK_COUNT.fetch_add(1, Ordering::Relaxed); 51 compiler_fence(Ordering::Acquire); 52 53 // 本地核心已经持有过锁,因此标记当前加锁获得的映射器为只读 54 let readonly = prev_count > 0; 55 56 return Self { mapper, readonly }; 57 } 58 59 /// @brief 锁定内核映射器, 并返回一个内核映射器对象 60 #[inline(always)] 61 pub fn lock() -> Self { 62 let cpuid = smp_get_processor_id() as usize; 63 let mapper = unsafe { PageMapper::current(PageTableKind::Kernel, LockedFrameAllocator) }; 64 return Self::lock_cpu(cpuid, mapper); 65 } 66 67 /// @brief 获取内核映射器的page mapper的可变引用。如果当前映射器为只读,则返回 None 68 #[inline(always)] 69 pub fn as_mut(&mut self) -> Option<&mut PageMapper> { 70 if self.readonly { 71 return None; 72 } else { 73 return Some(&mut self.mapper); 74 } 75 } 76 77 /// @brief 获取内核映射器的page mapper的不可变引用 78 #[inline(always)] 79 pub fn as_ref(&self) -> &PageMapper { 80 return &self.mapper; 81 } 82 83 /// 映射一段物理地址到指定的虚拟地址。 84 /// 85 /// ## 参数 86 /// 87 /// - `vaddr`: 要映射的虚拟地址 88 /// - `paddr`: 要映射的物理地址 89 /// - `size`: 要映射的大小(字节,必须是页大小的整数倍,否则会向上取整) 90 /// - `flags`: 页面标志 91 /// - `flush`: 是否刷新TLB 92 /// 93 /// ## 返回 94 /// 95 /// - 成功:返回Ok(()) 96 /// - 失败: 如果当前映射器为只读,则返回EAGAIN_OR_EWOULDBLOCK 97 pub unsafe fn map_phys_with_size( 98 &mut self, 99 mut vaddr: VirtAddr, 100 mut paddr: PhysAddr, 101 size: usize, 102 flags: PageFlags<MMArch>, 103 flush: bool, 104 ) -> Result<(), SystemError> { 105 if self.readonly { 106 return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); 107 } 108 109 let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE); 110 // kdebug!("kernel mapper: map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}"); 111 112 for _ in 0..count.data() { 113 let flusher = self.mapper.map_phys(vaddr, paddr, flags).unwrap(); 114 115 if flush { 116 flusher.flush(); 117 } 118 119 vaddr += MMArch::PAGE_SIZE; 120 paddr += MMArch::PAGE_SIZE; 121 } 122 return Ok(()); 123 } 124 } 125 126 impl Drop for KernelMapper { 127 fn drop(&mut self) { 128 // 为了防止fetch_sub和store之间,由于中断,导致store错误清除了owner,导致错误,因此需要关中断。 129 let flags = local_irq_save(); 130 let prev_count = KERNEL_MAPPER_LOCK_COUNT.fetch_sub(1, Ordering::Relaxed); 131 if prev_count == 1 { 132 KERNEL_MAPPER_LOCK_OWNER.store(KERNEL_MAPPER_NO_PROCESSOR, Ordering::Release); 133 } 134 local_irq_restore(flags); 135 compiler_fence(Ordering::Release); 136 } 137 } 138 139 impl Deref for KernelMapper { 140 type Target = PageMapper; 141 142 fn deref(&self) -> &Self::Target { 143 return self.as_ref(); 144 } 145 } 146