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