xref: /DragonOS/kernel/src/arch/riscv64/mm/mod.rs (revision 471d65cf158c9bf741c21f5d0ab92efe7bf1c3d4)
1 use riscv::register::satp;
2 use sbi_rt::{HartMask, SbiRet};
3 use system_error::SystemError;
4 
5 use crate::{
6     arch::MMArch,
7     driver::open_firmware::fdt::open_firmware_fdt_driver,
8     libs::spinlock::SpinLock,
9     mm::{
10         allocator::{
11             buddy::BuddyAllocator,
12             page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage, PhysPageFrame},
13         },
14         kernel_mapper::KernelMapper,
15         page::{PageEntry, PageFlags, PAGE_1G_SHIFT},
16         ucontext::UserMapper,
17         MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr,
18     },
19     smp::cpu::ProcessorId,
20 };
21 
22 use self::init::riscv_mm_init;
23 
24 pub mod bump;
25 pub(super) mod init;
26 
27 pub type PageMapper = crate::mm::page::PageMapper<RiscV64MMArch, LockedFrameAllocator>;
28 
29 /// 内核起始物理地址
30 pub(self) static mut KERNEL_BEGIN_PA: PhysAddr = PhysAddr::new(0);
31 /// 内核结束的物理地址
32 pub(self) static mut KERNEL_END_PA: PhysAddr = PhysAddr::new(0);
33 /// 内核起始虚拟地址
34 pub(self) static mut KERNEL_BEGIN_VA: VirtAddr = VirtAddr::new(0);
35 /// 内核结束虚拟地址
36 pub(self) static mut KERNEL_END_VA: VirtAddr = VirtAddr::new(0);
37 
38 pub(self) static INNER_ALLOCATOR: SpinLock<Option<BuddyAllocator<MMArch>>> = SpinLock::new(None);
39 
40 /// RiscV64的内存管理架构结构体(sv39)
41 #[derive(Debug, Clone, Copy, Hash)]
42 pub struct RiscV64MMArch;
43 
44 impl RiscV64MMArch {
45     /// 使远程cpu的TLB中,指定地址范围的页失效
46     pub fn remote_invalidate_page(
47         cpu: ProcessorId,
48         address: VirtAddr,
49         size: usize,
50     ) -> Result<(), SbiRet> {
51         let r = sbi_rt::remote_sfence_vma(Into::into(cpu), address.data(), size);
52         if r.is_ok() {
53             return Ok(());
54         } else {
55             return Err(r);
56         }
57     }
58 
59     /// 使指定远程cpu的TLB中,所有范围的页失效
60     pub fn remote_invalidate_all(cpu: ProcessorId) -> Result<(), SbiRet> {
61         let r = Self::remote_invalidate_page(
62             cpu,
63             VirtAddr::new(0),
64             1 << RiscV64MMArch::ENTRY_ADDRESS_SHIFT,
65         );
66 
67         return r;
68     }
69 
70     pub fn remote_invalidate_all_with_mask(mask: HartMask) -> Result<(), SbiRet> {
71         let r = sbi_rt::remote_sfence_vma(mask, 0, 1 << RiscV64MMArch::ENTRY_ADDRESS_SHIFT);
72         if r.is_ok() {
73             return Ok(());
74         } else {
75             return Err(r);
76         }
77     }
78 }
79 
80 /// 内核空间起始地址在顶层页表中的索引
81 const KERNEL_TOP_PAGE_ENTRY_NO: usize = (RiscV64MMArch::PHYS_OFFSET
82     & ((1 << RiscV64MMArch::ENTRY_ADDRESS_SHIFT) - 1))
83     >> (RiscV64MMArch::ENTRY_ADDRESS_SHIFT - RiscV64MMArch::PAGE_ENTRY_SHIFT);
84 
85 impl MemoryManagementArch for RiscV64MMArch {
86     /// riscv64暂不支持缺页中断
87     const PAGE_FAULT_ENABLED: bool = false;
88 
89     const PAGE_SHIFT: usize = 12;
90 
91     const PAGE_ENTRY_SHIFT: usize = 9;
92 
93     /// sv39分页只有三级
94     const PAGE_LEVELS: usize = 3;
95 
96     const ENTRY_ADDRESS_SHIFT: usize = 39;
97 
98     const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT
99         | Self::ENTRY_FLAG_READWRITE
100         | Self::ENTRY_FLAG_DIRTY
101         | Self::ENTRY_FLAG_ACCESSED
102         | Self::ENTRY_FLAG_GLOBAL;
103 
104     const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT;
105 
106     const ENTRY_FLAG_PRESENT: usize = 1 << 0;
107 
108     const ENTRY_FLAG_READONLY: usize = (1 << 1);
109 
110     const ENTRY_FLAG_WRITEABLE: usize = (1 << 2);
111 
112     const ENTRY_FLAG_READWRITE: usize = (1 << 2) | (1 << 1);
113 
114     const ENTRY_FLAG_USER: usize = (1 << 4);
115     const ENTRY_ADDRESS_MASK: usize = Self::ENTRY_ADDRESS_SIZE - (1 << 10);
116     const ENTRY_FLAG_WRITE_THROUGH: usize = (2 << 61);
117 
118     const ENTRY_FLAG_CACHE_DISABLE: usize = (2 << 61);
119 
120     const ENTRY_FLAG_NO_EXEC: usize = 0;
121 
122     const ENTRY_FLAG_EXEC: usize = (1 << 3);
123     const ENTRY_FLAG_ACCESSED: usize = (1 << 6);
124     const ENTRY_FLAG_DIRTY: usize = (1 << 7);
125     const ENTRY_FLAG_GLOBAL: usize = (1 << 5);
126 
127     const PHYS_OFFSET: usize = 0xffff_ffc0_0000_0000;
128     const KERNEL_LINK_OFFSET: usize = 0x1000000;
129 
130     const USER_END_VADDR: crate::mm::VirtAddr = VirtAddr::new(0x0000_003f_ffff_ffff);
131 
132     const USER_BRK_START: crate::mm::VirtAddr = VirtAddr::new(0x0000_001f_ffff_ffff);
133 
134     const USER_STACK_START: crate::mm::VirtAddr = VirtAddr::new(0x0000_001f_ffa0_0000);
135 
136     /// 在距离sv39的顶端还有64M的位置,设置为FIXMAP的起始地址
137     const FIXMAP_START_VADDR: VirtAddr = VirtAddr::new(0xffff_ffff_fc00_0000);
138     /// 设置1MB的fixmap空间
139     const FIXMAP_SIZE: usize = 256 * 4096;
140 
141     /// 在距离sv39的顶端还有2G的位置,设置为MMIO空间的起始地址
142     const MMIO_BASE: VirtAddr = VirtAddr::new(0xffff_ffff_8000_0000);
143     /// 设置1g的MMIO空间
144     const MMIO_SIZE: usize = 1 << PAGE_1G_SHIFT;
145 
146     const ENTRY_FLAG_HUGE_PAGE: usize = Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_READWRITE;
147 
148     #[inline(never)]
149     unsafe fn init() {
150         riscv_mm_init().expect("init kernel memory management architecture failed");
151     }
152 
153     unsafe fn arch_post_init() {
154         // 映射fdt
155         open_firmware_fdt_driver()
156             .map_fdt()
157             .expect("openfirmware map fdt failed");
158     }
159 
160     unsafe fn invalidate_page(address: VirtAddr) {
161         riscv::asm::sfence_vma(0, address.data());
162     }
163 
164     unsafe fn invalidate_all() {
165         riscv::asm::sfence_vma_all();
166     }
167 
168     unsafe fn table(_table_kind: PageTableKind) -> PhysAddr {
169         // phys page number
170         let ppn = riscv::register::satp::read().ppn();
171 
172         let paddr = PhysPageFrame::from_ppn(ppn).phys_address();
173 
174         return paddr;
175     }
176 
177     unsafe fn set_table(_table_kind: PageTableKind, table: PhysAddr) {
178         let ppn = PhysPageFrame::new(table).ppn();
179         riscv::asm::sfence_vma_all();
180         satp::set(satp::Mode::Sv39, 0, ppn);
181     }
182 
183     fn virt_is_valid(virt: VirtAddr) -> bool {
184         virt.is_canonical()
185     }
186 
187     fn initial_page_table() -> PhysAddr {
188         todo!()
189     }
190 
191     fn setup_new_usermapper() -> Result<UserMapper, SystemError> {
192         let new_umapper: crate::mm::page::PageMapper<MMArch, LockedFrameAllocator> = unsafe {
193             PageMapper::create(PageTableKind::User, LockedFrameAllocator)
194                 .ok_or(SystemError::ENOMEM)?
195         };
196 
197         let current_ktable: KernelMapper = KernelMapper::lock();
198         let copy_mapping = |pml4_entry_no| unsafe {
199             let entry: PageEntry<RiscV64MMArch> = current_ktable
200                 .table()
201                 .entry(pml4_entry_no)
202                 .unwrap_or_else(|| panic!("entry {} not found", pml4_entry_no));
203             new_umapper.table().set_entry(pml4_entry_no, entry)
204         };
205 
206         // 复制内核的映射
207         for pml4_entry_no in KERNEL_TOP_PAGE_ENTRY_NO..512 {
208             copy_mapping(pml4_entry_no);
209         }
210 
211         return Ok(crate::mm::ucontext::UserMapper::new(new_umapper));
212     }
213 
214     unsafe fn phys_2_virt(phys: PhysAddr) -> Option<VirtAddr> {
215         // riscv的内核文件所占用的空间,由于重定位而导致不满足线性偏移量的关系
216         // 因此这里需要特殊处理
217         if phys >= KERNEL_BEGIN_PA && phys < KERNEL_END_PA {
218             let r = KERNEL_BEGIN_VA + (phys - KERNEL_BEGIN_PA);
219             return Some(r);
220         }
221 
222         if let Some(vaddr) = phys.data().checked_add(Self::PHYS_OFFSET) {
223             return Some(VirtAddr::new(vaddr));
224         } else {
225             return None;
226         }
227     }
228 
229     unsafe fn virt_2_phys(virt: VirtAddr) -> Option<PhysAddr> {
230         if virt >= KERNEL_BEGIN_VA && virt < KERNEL_END_VA {
231             let r = KERNEL_BEGIN_PA + (virt - KERNEL_BEGIN_VA);
232             return Some(r);
233         }
234 
235         if let Some(paddr) = virt.data().checked_sub(Self::PHYS_OFFSET) {
236             let r = PhysAddr::new(paddr);
237             return Some(r);
238         } else {
239             return None;
240         }
241     }
242 
243     fn make_entry(paddr: PhysAddr, page_flags: usize) -> usize {
244         let ppn = PhysPageFrame::new(paddr).ppn();
245         let r = ((ppn & ((1 << 54) - 1)) << 10) | page_flags;
246         return r;
247     }
248 
249     fn vma_access_permitted(
250         _vma: alloc::sync::Arc<crate::mm::ucontext::LockedVMA>,
251         _write: bool,
252         _execute: bool,
253         _foreign: bool,
254     ) -> bool {
255         true
256     }
257 }
258 
259 impl VirtAddr {
260     /// 判断虚拟地址是否合法
261     #[inline(always)]
262     pub fn is_canonical(self) -> bool {
263         let x = self.data() & RiscV64MMArch::PHYS_OFFSET;
264         // 如果x为0,说明虚拟地址的高位为0,是合法的用户地址
265         // 如果x为PHYS_OFFSET,说明虚拟地址的高位全为1,是合法的内核地址
266         return x == 0 || x == RiscV64MMArch::PHYS_OFFSET;
267     }
268 }
269 
270 /// 获取内核地址默认的页面标志
271 pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(_virt: VirtAddr) -> PageFlags<A> {
272     PageFlags::from_data(RiscV64MMArch::ENTRY_FLAG_DEFAULT_PAGE)
273         .set_user(false)
274         .set_execute(true)
275 }
276 
277 /// 全局的页帧分配器
278 #[derive(Debug, Clone, Copy, Hash)]
279 pub struct LockedFrameAllocator;
280 
281 impl FrameAllocator for LockedFrameAllocator {
282     unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
283         if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
284             return allocator.allocate(count);
285         } else {
286             return None;
287         }
288     }
289 
290     unsafe fn free(&mut self, address: crate::mm::PhysAddr, count: PageFrameCount) {
291         assert!(count.data().is_power_of_two());
292         if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
293             return allocator.free(address, count);
294         }
295     }
296 
297     unsafe fn usage(&self) -> PageFrameUsage {
298         if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
299             return allocator.usage();
300         } else {
301             panic!("usage error");
302         }
303     }
304 }
305