xref: /DragonOS/kernel/src/mm/kernel_mapper.rs (revision 196b75dc17b5cc2ed84301bce776e496ddfe1ed1)
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