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