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