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