diff options
Diffstat (limited to 'dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc')
| -rw-r--r-- | dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc | 276 |
1 files changed, 131 insertions, 145 deletions
diff --git a/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc b/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc index 08caed82..8e80c4d8 100644 --- a/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc +++ b/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc @@ -1,156 +1,142 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - File: HalPagingMgr.cc - Purpose: Platform Paging Manager. + File: HalPagingMgr.cc + Purpose: Platform Paging Manager. ------------------------------------------- */ #include <HALKit/AMD64/Paging.h> #include <HALKit/AMD64/Processor.h> -namespace Kernel::HAL -{ - namespace Detail - { - /// @brief Page Table Entry for AMD64. - struct PTE - { - UInt64 Present : 1; - UInt64 Wr : 1; - UInt64 User : 1; - UInt64 Pwt : 1; // Page-level Write-Through - UInt64 Pcd : 1; // Page-level Cache Disable - UInt64 Accessed : 1; - UInt64 Dirty : 1; - UInt64 Pat : 1; // Page Attribute Table (or PS for PDE) - UInt64 Global : 1; - UInt64 Ignored1 : 3; // Available to software - UInt64 PhysicalAddress : 40; // Physical page frame address (bits 12–51) - UInt64 Ignored2 : 7; // More software bits / reserved - UInt64 ProtectionKey : 4; // Optional (if PKU enabled) - UInt64 Reserved : 1; // Usually reserved - UInt64 Nx : 1; // No Execute - }; - } // namespace Detail - - /***********************************************************************************/ - /// \brief Retrieve the page status of a PTE. - /// \param pte Page Table Entry pointer. - /***********************************************************************************/ - STATIC Void mmi_page_status(Detail::PTE* pte) - { - (Void)(kout << (pte->Present ? "Present" : "Not Present") << kendl); - (Void)(kout << (pte->Wr ? "W/R" : "Not W/R") << kendl); - (Void)(kout << (pte->Nx ? "NX" : "Not NX") << kendl); - (Void)(kout << (pte->User ? "User" : "Not User") << kendl); - (Void)(kout << (pte->Pcd ? "Not Cached" : "Cached") << kendl); - (Void)(kout << (pte->Accessed ? "Accessed" : "Not Accessed") << kendl); - (Void)(kout << hex_number(pte->PhysicalAddress) << kendl); - (Void)(kout << (pte->ProtectionKey ? "Protected" : "Not Protected/PKU Disabled") << kendl); - } - - /***********************************************************************************/ - /// @brief Gets a physical address from a virtual address. - /// @param virt a valid virtual address. - /// @return Physical address. - /***********************************************************************************/ - UIntPtr hal_get_phys_address(VoidPtr virt) - { - const UInt64 kVMAddr = (UInt64)virt; - const UInt64 kMask9Bits = 0x1FFULL; - const UInt64 kPageOffsetMask = 0xFFFULL; - - UInt64 cr3 = (UInt64)hal_read_cr3() & ~kPageOffsetMask; - - // Level 4 - auto pml4 = reinterpret_cast<UInt64*>(cr3); - UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9Bits]; - - if (!(pml4e & 1)) - return 0; - - // Level 3 - auto pdpt = reinterpret_cast<UInt64*>(pml4e & ~kPageOffsetMask); - UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9Bits]; - - if (!(pdpte & 1)) - return 0; - - // Level 2 - auto pd = reinterpret_cast<UInt64*>(pdpte & ~kPageOffsetMask); - UInt64 pde = pd[(kVMAddr >> 21) & kMask9Bits]; - - if (!(pde & 1)) - return 0; - - // 1 GiB page support - if (pde & (1 << 7)) - { - return (pde & ~((1ULL << 30) - 1)) | (kVMAddr & ((1ULL << 30) - 1)); - } - - // Level 1 - auto pt = reinterpret_cast<UInt64*>(pde & ~kPageOffsetMask); - Detail::PTE* pte = (Detail::PTE*)pt[(kVMAddr >> 12) & kMask9Bits]; - - if (!pte->Present) - return 0; - - mmi_page_status((Detail::PTE*)pte); - - return pte->PhysicalAddress; - } - - /***********************************************************************************/ - /// @brief Maps or allocates a page from virtual_address. - /// @param virtual_address a valid virtual address. - /// @param phys_addr point to physical address. - /// @param flags the flags to put on the page. - /// @return Status code of page manipulation process. - /***********************************************************************************/ - EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags) - { - const UInt64 kVMAddr = (UInt64)virtual_address; - constexpr UInt64 kMask9 = 0x1FF; - constexpr UInt64 kPageMask = 0xFFF; - - UInt64 cr3 = (UIntPtr)hal_read_cr3() & ~kPageMask; - - auto pml4 = reinterpret_cast<UInt64*>(cr3); - UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9]; - - if (!(pml4e & 1)) - return kErrorInvalidData; - - UInt64* pdpt = reinterpret_cast<UInt64*>(pml4e & ~kPageMask); - UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9]; - - if (!(pdpte & 1)) - return kErrorInvalidData; - - UInt64* pd = reinterpret_cast<UInt64*>(pdpte & ~kPageMask); - UInt64 pde = pd[(kVMAddr >> 21) & kMask9]; - - if (!(pde & 1)) - return kErrorInvalidData; - - UInt64* pt = reinterpret_cast<UInt64*>(pde & ~kPageMask); - Detail::PTE* pte = (Detail::PTE*)pt[(kVMAddr >> 12) & kMask9]; - - pte->Present = !!(flags & kMMFlagsPresent); - pte->Wr = !!(flags & kMMFlagsWr); - pte->User = !!(flags & kMMFlagsUser); - pte->Nx = !!(flags & kMMFlagsNX); - pte->Pcd = !!(flags & kMMFlagsPCD); - pte->Pwt = !!(flags & kMMFlagsPwt); - pte->PhysicalAddress = ((UIntPtr)(physical_address)); - - hal_invl_tlb(virtual_address); +namespace Kernel::HAL { +namespace Detail { + /// @brief Page Table Entry for AMD64. + struct PTE { + UInt64 Present : 1; + UInt64 Wr : 1; + UInt64 User : 1; + UInt64 Pwt : 1; // Page-level Write-Through + UInt64 Pcd : 1; // Page-level Cache Disable + UInt64 Accessed : 1; + UInt64 Dirty : 1; + UInt64 Pat : 1; // Page Attribute Table (or PS for PDE) + UInt64 Global : 1; + UInt64 Ignored1 : 3; // Available to software + UInt64 PhysicalAddress : 40; // Physical page frame address (bits 12–51) + UInt64 Ignored2 : 7; // More software bits / reserved + UInt64 ProtectionKey : 4; // Optional (if PKU enabled) + UInt64 Reserved : 1; // Usually reserved + UInt64 Nx : 1; // No Execute + }; +} // namespace Detail + +/***********************************************************************************/ +/// \brief Retrieve the page status of a PTE. +/// \param pte Page Table Entry pointer. +/***********************************************************************************/ +STATIC Void mmi_page_status(Detail::PTE* pte) { + (Void)(kout << (pte->Present ? "Present" : "Not Present") << kendl); + (Void)(kout << (pte->Wr ? "W/R" : "Not W/R") << kendl); + (Void)(kout << (pte->Nx ? "NX" : "Not NX") << kendl); + (Void)(kout << (pte->User ? "User" : "Not User") << kendl); + (Void)(kout << (pte->Pcd ? "Not Cached" : "Cached") << kendl); + (Void)(kout << (pte->Accessed ? "Accessed" : "Not Accessed") << kendl); + (Void)(kout << hex_number(pte->PhysicalAddress) << kendl); + (Void)(kout << (pte->ProtectionKey ? "Protected" : "Not Protected/PKU Disabled") << kendl); +} + +/***********************************************************************************/ +/// @brief Gets a physical address from a virtual address. +/// @param virt a valid virtual address. +/// @return Physical address. +/***********************************************************************************/ +UIntPtr hal_get_phys_address(VoidPtr virt) { + const UInt64 kVMAddr = (UInt64) virt; + const UInt64 kMask9Bits = 0x1FFULL; + const UInt64 kPageOffsetMask = 0xFFFULL; + + UInt64 cr3 = (UInt64) hal_read_cr3() & ~kPageOffsetMask; + + // Level 4 + auto pml4 = reinterpret_cast<UInt64*>(cr3); + UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9Bits]; + + if (!(pml4e & 1)) return 0; + + // Level 3 + auto pdpt = reinterpret_cast<UInt64*>(pml4e & ~kPageOffsetMask); + UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9Bits]; + + if (!(pdpte & 1)) return 0; + + // Level 2 + auto pd = reinterpret_cast<UInt64*>(pdpte & ~kPageOffsetMask); + UInt64 pde = pd[(kVMAddr >> 21) & kMask9Bits]; + + if (!(pde & 1)) return 0; + + // 1 GiB page support + if (pde & (1 << 7)) { + return (pde & ~((1ULL << 30) - 1)) | (kVMAddr & ((1ULL << 30) - 1)); + } + + // Level 1 + auto pt = reinterpret_cast<UInt64*>(pde & ~kPageOffsetMask); + Detail::PTE* pte = (Detail::PTE*) pt[(kVMAddr >> 12) & kMask9Bits]; + + if (!pte->Present) return 0; + + mmi_page_status((Detail::PTE*) pte); + + return pte->PhysicalAddress; +} + +/***********************************************************************************/ +/// @brief Maps or allocates a page from virtual_address. +/// @param virtual_address a valid virtual address. +/// @param phys_addr point to physical address. +/// @param flags the flags to put on the page. +/// @return Status code of page manipulation process. +/***********************************************************************************/ +EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags) { + const UInt64 kVMAddr = (UInt64) virtual_address; + constexpr UInt64 kMask9 = 0x1FF; + constexpr UInt64 kPageMask = 0xFFF; + + UInt64 cr3 = (UIntPtr) hal_read_cr3() & ~kPageMask; + + auto pml4 = reinterpret_cast<UInt64*>(cr3); + UInt64 pml4e = pml4[(kVMAddr >> 39) & kMask9]; + + if (!(pml4e & 1)) return kErrorInvalidData; + + UInt64* pdpt = reinterpret_cast<UInt64*>(pml4e & ~kPageMask); + UInt64 pdpte = pdpt[(kVMAddr >> 30) & kMask9]; + + if (!(pdpte & 1)) return kErrorInvalidData; + + UInt64* pd = reinterpret_cast<UInt64*>(pdpte & ~kPageMask); + UInt64 pde = pd[(kVMAddr >> 21) & kMask9]; + + if (!(pde & 1)) return kErrorInvalidData; + + UInt64* pt = reinterpret_cast<UInt64*>(pde & ~kPageMask); + Detail::PTE* pte = (Detail::PTE*) pt[(kVMAddr >> 12) & kMask9]; + + pte->Present = !!(flags & kMMFlagsPresent); + pte->Wr = !!(flags & kMMFlagsWr); + pte->User = !!(flags & kMMFlagsUser); + pte->Nx = !!(flags & kMMFlagsNX); + pte->Pcd = !!(flags & kMMFlagsPCD); + pte->Pwt = !!(flags & kMMFlagsPwt); + pte->PhysicalAddress = ((UIntPtr) (physical_address)); + + hal_invl_tlb(virtual_address); - mmi_page_status(pte); + mmi_page_status(pte); - return kErrorSuccess; - } -} // namespace Kernel::HAL + return kErrorSuccess; +} +} // namespace Kernel::HAL |
