| 72 | } |
| 73 | |
| 74 | auto VirtualMemory::MapPage(void* page_dir, void* virtual_addr, |
| 75 | void* physical_addr, uint32_t flags) |
| 76 | -> Expected<void> { |
| 77 | assert(page_dir != nullptr && "MapPage: page_dir is null"); |
| 78 | |
| 79 | // 查找页表项,如果不存在则分配 |
| 80 | auto pte_result = FindPageTableEntry(page_dir, virtual_addr, true); |
| 81 | if (!pte_result.has_value()) { |
| 82 | return std::unexpected(Error(ErrorCode::kVmMapFailed)); |
| 83 | } |
| 84 | |
| 85 | auto pte = pte_result.value(); |
| 86 | |
| 87 | // 检查是否已经映射且标志位相同 |
| 88 | if (cpu_io::virtual_memory::IsPageTableEntryValid(*pte)) { |
| 89 | // 如果物理地址和标志位都相同,则认为是重复映射(警告但不失败) |
| 90 | auto existing_pa = cpu_io::virtual_memory::PageTableEntryToPhysical(*pte); |
| 91 | if (existing_pa == reinterpret_cast<uint64_t>(physical_addr) && |
| 92 | (*pte & ((1ULL << cpu_io::virtual_memory::kPteAttributeBits) - 1)) == |
| 93 | flags) { |
| 94 | klog::Debug( |
| 95 | "MapPage: duplicate va = {:#x}, pa = {:#X}, flags = {:#X}, skip", |
| 96 | static_cast<uint64_t>(reinterpret_cast<uintptr_t>(virtual_addr)), |
| 97 | static_cast<uint64_t>(existing_pa), static_cast<uint64_t>(flags)); |
| 98 | // 重复映射,但不是错误 |
| 99 | return {}; |
| 100 | } |
| 101 | klog::Warn( |
| 102 | "MapPage: remap va = {:#x} from pa = {:#X} to pa = {:#x}", |
| 103 | static_cast<uint64_t>(reinterpret_cast<uintptr_t>(virtual_addr)), |
| 104 | static_cast<uint64_t>(existing_pa), |
| 105 | static_cast<uint64_t>(reinterpret_cast<uintptr_t>(physical_addr))); |
| 106 | } |
| 107 | |
| 108 | // 设置页表项 |
| 109 | *pte = cpu_io::virtual_memory::PhysicalToPageTableEntry( |
| 110 | reinterpret_cast<uint64_t>(physical_addr), flags); |
| 111 | // 刷新 TLB |
| 112 | cpu_io::virtual_memory::FlushTLBAll(); |
| 113 | |
| 114 | return {}; |
| 115 | } |
| 116 | |
| 117 | auto VirtualMemory::UnmapPage(void* page_dir, void* virtual_addr) |
| 118 | -> Expected<void> { |