/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #ifndef __FENNIX_KERNEL_MEMORY_TABLE_H__ #define __FENNIX_KERNEL_MEMORY_TABLE_H__ #include namespace Memory { /** * @brief https://wiki.osdev.org/images/4/41/64-bit_page_tables1.png * @brief https://wiki.osdev.org/images/6/6b/64-bit_page_tables2.png */ enum PTFlag { /** @brief Present */ P = 1 << 0, /** @brief Read/Write */ RW = 1 << 1, /** @brief User/Supervisor */ US = 1 << 2, /** @brief Write-Through */ PWT = 1 << 3, /** @brief Cache Disable */ PCD = 1 << 4, /** @brief Accessed */ A = 1 << 5, /** @brief Dirty */ D = 1 << 6, /** @brief Page Size */ PS = 1 << 7, /** @brief Global */ G = 1 << 8, /** @brief Available 0 */ CoW = 1 << 9, /** @brief Available 1 */ KRsv = 1 << 10, /** @brief Available 2 */ AVL2 = 1 << 11, /** @brief Page Attribute Table */ PAT = 1 << 12, /** @brief Available 3 */ AVL3 = (uint64_t)1 << 52, /** @brief Available 4 */ AVL4 = (uint64_t)1 << 53, /** @brief Available 5 */ AVL5 = (uint64_t)1 << 54, /** @brief Available 6 */ AVL6 = (uint64_t)1 << 55, /** @brief Available 7 */ AVL7 = (uint64_t)1 << 56, /** @brief Available 8 */ AVL8 = (uint64_t)1 << 57, /** @brief Available 9 */ AVL9 = (uint64_t)1 << 58, /** @brief Protection Key 0 */ PK0 = (uint64_t)1 << 59, /** @brief Protection Key 1 */ PK1 = (uint64_t)1 << 60, /** @brief Protection Key 2 */ PK2 = (uint64_t)1 << 61, /** @brief Protection Key 3 */ PK3 = (uint64_t)1 << 62, /** @brief Execute Disable */ XD = (uint64_t)1 << 63 }; union __packed PageTableEntry { struct { #if defined(a64) uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t Dirty : 1; // 6 uintptr_t PageAttributeTable : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t Address : 40; // 12-51 uintptr_t Available3 : 1; // 52 uintptr_t Available4 : 1; // 53 uintptr_t Available5 : 1; // 54 uintptr_t Available6 : 1; // 55 uintptr_t Available7 : 1; // 56 uintptr_t Available8 : 1; // 57 uintptr_t Available9 : 1; // 58 uintptr_t ProtectionKey : 4; // 59-62 uintptr_t ExecuteDisable : 1; // 63 #elif defined(a32) uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t Dirty : 1; // 6 uintptr_t PageAttributeTable : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t Address : 20; // 12-31 #elif defined(aa64) #endif }; uintptr_t raw = 0; /** @brief Set Address */ void SetAddress(uintptr_t _Address) { #if defined(a64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #elif defined(a32) _Address &= 0x000FFFFF; this->raw &= 0xFFC00003; this->raw |= (_Address << 12); #elif defined(aa64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #endif } /** @brief Get Address */ uintptr_t GetAddress() { #if defined(a64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #elif defined(a32) return ((uintptr_t)(this->raw & 0x003FFFFF000) >> 12); #elif defined(aa64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #endif } }; struct __packed PageTableEntryPtr { #if defined(a64) PageTableEntry Entries[512]; #elif defined(a32) PageTableEntry Entries[1024]; #elif defined(aa64) #endif }; union __packed PageDirectoryEntry { #if defined(a64) struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t PageSize : 1; // 7 uintptr_t KernelReserve : 1; // 8 uintptr_t Available2 : 1; // 9 uintptr_t Available3 : 1; // 10 uintptr_t Available4 : 1; // 11 uintptr_t Address : 40; // 12-51 uintptr_t Available5 : 1; // 52 uintptr_t Available6 : 1; // 53 uintptr_t Available7 : 1; // 54 uintptr_t Available8 : 1; // 55 uintptr_t Available9 : 1; // 56 uintptr_t Available10 : 1; // 57 uintptr_t Available11 : 1; // 58 uintptr_t Available12 : 1; // 59 uintptr_t Available13 : 1; // 60 uintptr_t Available14 : 1; // 61 uintptr_t Available15 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t Dirty : 1; // 6 uintptr_t PageSize : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t PageAttributeTable : 1; // 12 uintptr_t Reserved0 : 8; // 13-20 uintptr_t Address : 31; // 21-51 uintptr_t Available3 : 1; // 52 uintptr_t Available4 : 1; // 53 uintptr_t Available5 : 1; // 54 uintptr_t Available6 : 1; // 55 uintptr_t Available7 : 1; // 56 uintptr_t Available8 : 1; // 57 uintptr_t Available9 : 1; // 58 uintptr_t ProtectionKey : 4; // 59-62 uintptr_t ExecuteDisable : 1; // 63 } TwoMiB; #elif defined(a32) struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t PageSize : 1; // 7 uintptr_t KernelReserve : 1; // 8 uintptr_t Available2 : 1; // 9 uintptr_t Available3 : 1; // 10 uintptr_t Available4 : 1; // 11 uintptr_t Address : 20; // 12-31 }; struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t Dirty : 1; // 6 uintptr_t PageSize : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t PageAttributeTable : 1; // 12 uintptr_t Address0 : 8; // 13-20 uintptr_t Reserved0 : 1; // 21 uintptr_t Address1 : 10; // 22-31 } FourMiB; #elif defined(aa64) #endif uintptr_t raw = 0; /** @brief Set PageTableEntryPtr address */ void SetAddress(uintptr_t _Address) { #if defined(a64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #elif defined(a32) _Address &= 0x000FFFFF; this->raw &= 0xFFC00003; this->raw |= (_Address << 12); #elif defined(aa64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #endif } /** @brief Get PageTableEntryPtr address */ uintptr_t GetAddress() { #if defined(a64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #elif defined(a32) return ((uintptr_t)(this->raw & 0x003FFFFF000) >> 12); #elif defined(aa64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #endif } }; struct __packed PageDirectoryEntryPtr { PageDirectoryEntry Entries[512]; }; union __packed PageDirectoryPointerTableEntry { #if defined(a64) struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t PageSize : 1; // 7 uintptr_t KernelReserve : 1; // 8 uintptr_t Available2 : 1; // 9 uintptr_t Available3 : 1; // 10 uintptr_t Available4 : 1; // 11 uintptr_t Address : 40; // 12-51 uintptr_t Available5 : 1; // 52 uintptr_t Available6 : 1; // 53 uintptr_t Available7 : 1; // 54 uintptr_t Available8 : 1; // 55 uintptr_t Available9 : 1; // 56 uintptr_t Available10 : 1; // 57 uintptr_t Available11 : 1; // 58 uintptr_t Available12 : 1; // 59 uintptr_t Available13 : 1; // 60 uintptr_t Available14 : 1; // 61 uintptr_t Available15 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t Dirty : 1; // 6 uintptr_t PageSize : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t PageAttributeTable : 1; // 12 uintptr_t Reserved0 : 17; // 13-29 uintptr_t Address : 22; // 30-51 uintptr_t Available3 : 1; // 52 uintptr_t Available4 : 1; // 53 uintptr_t Available5 : 1; // 54 uintptr_t Available6 : 1; // 55 uintptr_t Available7 : 1; // 56 uintptr_t Available8 : 1; // 57 uintptr_t Available9 : 1; // 58 uintptr_t ProtectionKey : 4; // 59-62 uintptr_t ExecuteDisable : 1; // 63 } OneGiB; #elif defined(aa64) #endif uintptr_t raw = 0; /** @brief Set PageDirectoryEntryPtr address */ void SetAddress(uintptr_t _Address) { #if defined(a64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #elif defined(aa64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #endif } /** @brief Get PageDirectoryEntryPtr address */ uintptr_t GetAddress() { #if defined(a64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #elif defined(a32) return 0; #elif defined(aa64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #endif } }; struct __packed PageDirectoryPointerTableEntryPtr { PageDirectoryPointerTableEntry Entries[512]; }; union __packed PageMapLevel4 { #if defined(a64) struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t Reserved0 : 1; // 7 uintptr_t KernelReserve : 1; // 8 uintptr_t Available2 : 1; // 9 uintptr_t Available3 : 1; // 10 uintptr_t Available4 : 1; // 11 uintptr_t Address : 40; // 12-51 uintptr_t Available5 : 1; // 52 uintptr_t Available6 : 1; // 53 uintptr_t Available7 : 1; // 54 uintptr_t Available8 : 1; // 55 uintptr_t Available9 : 1; // 56 uintptr_t Available10 : 1; // 57 uintptr_t Available11 : 1; // 58 uintptr_t Available12 : 1; // 59 uintptr_t Available13 : 1; // 60 uintptr_t Available14 : 1; // 61 uintptr_t Available15 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; #elif defined(aa64) #endif uintptr_t raw = 0; /** @brief Set PageDirectoryPointerTableEntryPtr address */ void SetAddress(uintptr_t _Address) { #if defined(a64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #elif defined(aa64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #endif } /** @brief Get PageDirectoryPointerTableEntryPtr address */ uintptr_t GetAddress() { #if defined(a64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #elif defined(a32) return 0; #elif defined(aa64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #endif } }; struct __packed PageMapLevel4Ptr { PageMapLevel4 Entries[512]; }; union __packed PageMapLevel5 { #if defined(a64) struct { uintptr_t Present : 1; // 0 uintptr_t ReadWrite : 1; // 1 uintptr_t UserSupervisor : 1; // 2 uintptr_t WriteThrough : 1; // 3 uintptr_t CacheDisable : 1; // 4 uintptr_t Accessed : 1; // 5 uintptr_t Available0 : 1; // 6 uintptr_t Reserved0 : 1; // 7 uintptr_t KernelReserve : 1; // 8 uintptr_t Available1 : 1; // 9 uintptr_t Available2 : 1; // 10 uintptr_t Available3 : 1; // 11 uintptr_t Address : 40; // 12-51 uintptr_t Available4 : 1; // 52 uintptr_t Available5 : 1; // 53 uintptr_t Available6 : 1; // 54 uintptr_t Available7 : 1; // 55 uintptr_t Available8 : 1; // 56 uintptr_t Available9 : 1; // 57 uintptr_t Available10 : 1; // 58 uintptr_t Available11 : 1; // 59 uintptr_t Available12 : 1; // 60 uintptr_t Available13 : 1; // 61 uintptr_t Available14 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; #elif defined(aa64) #endif uintptr_t raw = 0; /** @brief Set PageMapLevel4Ptr address */ void SetAddress(uintptr_t _Address) { #if defined(a64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #elif defined(aa64) _Address &= 0x000000FFFFFFFFFF; this->raw &= 0xFFF0000000000FFF; this->raw |= (_Address << 12); #endif } /** @brief Get PageMapLevel4Ptr address */ uintptr_t GetAddress() { #if defined(a64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #elif defined(a32) return 0; #elif defined(aa64) return (this->raw & 0x000FFFFFFFFFF000) >> 12; #endif } }; class PageTable { public: #if defined(a64) PageMapLevel4 Entries[512]; #elif defined(a32) PageDirectoryEntry Entries[1024]; #elif defined(aa64) #endif /** * @brief Update CR3 with this PageTable */ void Update(); /** * @brief Fork this PageTable * * @return A new PageTable with the same content */ PageTable *Fork(); void *__getPhysical(void *Address); /** * @brief Get the Physical Address of a virtual address * * This function will return the physical address * of a virtual address and not the virtual address * of the current page table. This is intentional because * the kernel page table has 1:1 mapping for the free * memory. * * @tparam T * @param Address The virtual address * @return The physical address */ template T Get(T Address) { void *PhysAddr = __getPhysical((void *)Address); if (PhysAddr == nullptr) return {}; uintptr_t Diff = uintptr_t(Address); Diff &= 0xFFF; Diff = uintptr_t(PhysAddr) + Diff; return (T)Diff; } } __aligned(0x1000); } #endif // !__FENNIX_KERNEL_MEMORY_TABLE_H__