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