#include "paging.hpp"
#include "serial.hpp"
-// void os::paging::unmap(phys_ptr<PML4T> PLM4T, page* virt, std::uint64_t length) { }
-// void os::paging::map(phys_ptr<PML4T> PLM4T, page* virt, std::uint64_t length, phys_ptr<page> phys) { }
-template<int order> void print_mapping(const os::paging::paging_table<order>& table, std::uint64_t virt_address, bool show_higher_half) {
- for (std::size_t i = 0; i < (order == 3 && !show_higher_half ? 256 : 512); i++) {
- const auto& page = table.contents[i];
- if (!page.P()) { continue; }
- std::uint64_t new_virt = virt_address + i * (4096ul << (order * 9));
- new_virt |= ((new_virt & 0x0000800000000000) != 0 ? 0xFFFF000000000000 : 0);
- if (page.is_page()) {
- os::print(new_virt);
- os::print(" -> ");
- os::print(page.base_address().get_phys_addr());
- os::print(" (order ");
- os::printc(order + '0');
- os::print(")\n");
+namespace {
+void on_all_pages(const os::paging::PT& PT, void f(os::paging::page*, os::phys_ptr<os::paging::page>, std::size_t), std::size_t PT_virt_address) {
+ for (std::size_t i = 0; i < 512; i++) {
+ if (!PT.contents[i].P) {
+ continue;
+ }
+ std::uint64_t virt_address = PT_virt_address | (i * 0x1000ull);
+ f(reinterpret_cast<os::paging::page*>(virt_address), os::paging::get_page_base_address(PT.contents[i]), 0x1000ull);
+ }
+}
+void on_all_pages(const os::paging::PDT& PDT, void f(os::paging::page*, os::phys_ptr<os::paging::page>, std::size_t), std::size_t PDT_virt_address) {
+ for (std::size_t i = 0; i < 512; i++) {
+ if (!PDT.contents[i].page.P) {
+ continue;
+ }
+ std::uint64_t virt_address = PDT_virt_address | (i * 0x1000ull * 512ull);
+ if (os::paging::is_page(PDT.contents[i])) {
+ f(reinterpret_cast<os::paging::page*>(virt_address), os::paging::get_page_base_address(PDT.contents[i]), 0x1000ull * 512ull);
} else {
- if constexpr (order > 0) { // Will never be false when !page.is_page().
- print_mapping<order - 1>(*page.base_address(), new_virt, show_higher_half);
- }
+ on_all_pages(*os::paging::get_base_address(PDT.contents[i]), f, virt_address);
}
}
}
-void os::paging::print_mapping(const PML4T& PML4T, bool show_higher_half) {
- ::print_mapping(PML4T, 0, show_higher_half);
+void on_all_pages(const os::paging::PDPT& PDPT, void f(os::paging::page*, os::phys_ptr<os::paging::page>, std::size_t), std::size_t PDPT_virt_address) {
+ for (std::size_t i = 0; i < 512; i++) {
+ if (!PDPT.contents[i].page.P) {
+ continue;
+ }
+ std::uint64_t virt_address = PDPT_virt_address | (i * 0x1000ull * 512ull * 512ull);
+ if (os::paging::is_page(PDPT.contents[i])) {
+ f(reinterpret_cast<os::paging::page*>(virt_address), os::paging::get_page_base_address(PDPT.contents[i]), 0x1000ull * 512ull * 512ull);
+ } else {
+ on_all_pages(*os::paging::get_base_address(PDPT.contents[i]), f, virt_address);
+ }
+ }
+}
+}
+void os::paging::on_all_pages(const os::paging::PML4T& PML4T, void f(page*, phys_ptr<page>, std::size_t)) {
+ for (std::size_t i = 0; i < 512; i++) {
+ if (!PML4T.contents[i].P) {
+ continue;
+ }
+ std::uint64_t virt_address = (i < 256 ? 0x0000'0000'0000'0000 : 0xFFFF'8000'0000'0000) | (i * 0x1000ull * 512ull * 512ull * 512ull);
+ ::on_all_pages(*os::paging::get_base_address(PML4T.contents[i]), f, virt_address);
+ }
}
+
os::paging::page one_past_end_page_for_page_allocator;
os::paging::page_allocator_t os::paging::page_allocator(os::phys_ptr<os::paging::page>(reinterpret_cast<uintptr_t>(&one_past_end_page_for_page_allocator) - 0xFFFFFFFF80000000));
namespace os { namespace paging {
-template <int order>
-struct __attribute__((aligned(0x1000))) paging_table;
-
-template <int order>
-struct paging_entry {
-public:
- static_assert(order >= 0, "negative order for paging entry.");
- paging_entry(bool is_page) {
- os::assert(order != 0 || is_page, "4KiB defined as non-page.");
- if (order != 0 && is_page) {
- data |= 1 << 7; // Mark as smallest page.
- }
- }
- inline bool is_page() const {
- return order == 0 || (data & (1 << 7)) != 0;
- }
-
- inline bool NX() const {
- return (data & (1ul << 63)) != 0;
- }
- inline void NX(bool v) {
- data = (data & ~(1ul << 63)) | (v ? (1ul << 63) : 0);
- }
- inline unsigned PK() const {
- os::assert(is_page(), "read protection key of non-page.");
- return (data >> 52) & 0xF;
- }
- inline void PK(unsigned v) {
- os::assert(is_page(), "write to protection key of non-page.");
- os::assert((v & 0xF) == v, "incorrect protection key.");
- data = (data & ~(0xFul << 59)) | (std::uint64_t(v) << 59);
- }
- inline unsigned AVL_high() const {
- return (data >> 52) & (is_page() ? 0x7F : 0x7FF);
- }
- inline void AVL_high(unsigned v) {
- os::assert((v & (is_page() ? 0x7F : 0x7FF)) == v, "incorrect AVL high bits.");
- data = (data & ~((is_page() ? 0x7Ful : 0x7FFul) << 52)) | (std::uint64_t(v) << 52);
- }
- inline phys_ptr<paging_table<order - 1>> base_address() const {
- return phys_ptr<paging_table<order - 1>>{data & 0x000FFFFFFFFFF000 & ~(order != 0 && is_page() ? 1ul << 12 : 0ul)};
- }
- inline void base_address(phys_ptr<paging_table<order - 1>> v) {
- const std::uint64_t v_int = v.get_phys_addr();
- os::assert((v_int & 0x000FFFFFFFFFF000 & (0xFFFFFFFFFFFFF000 << (is_page() ? 9 * order : 0))) == v_int, "incorrect base address.");
- data = (data & ~0x000FFFFFFFFFF000ul & ~(order != 0 && is_page() ? 1ul << 12 : 0ul)) | v_int;
- }
- inline unsigned AVL_low() const {
- return (data >> 9) & 0x7;
- }
- inline void AVL_low(unsigned v) {
- os::assert((v & 0x7) == v, "incorrect AVL low bits");
- data = (data & ~(0x7ul << 9)) | (v << 9);
- }
- inline bool G() const {
- os::assert(is_page(), "read global bit of non-page.");
- return (data & (1 << 8)) != 0;
- }
- inline void G(bool v) {
- os::assert(is_page(), "write to global bit of non-page.");
- data = (data & ~(1ul << 8)) | (v ? 1 << 8 : 0);
- }
- inline bool PAT() const {
- os::assert(is_page(), "read PAT bit of non-page.");
- return (data & (1 << (order == 0 ? 7 : 12))) != 0;
- }
- inline void PAT(bool v) {
- os::assert(is_page(), "write to PAT bit of non-page.");
- data = (data & ~(1ul << (order == 0 ? 7 : 12))) | (v ? 1 << (order == 0 ? 7 : 12) : 0);
- }
- inline bool D() const {
- os::assert(is_page(), "read dirty bit of non-page.");
- return (data & (1 << 6)) != 0;
- }
- inline void D(bool v) {
- os::assert(is_page(), "write to dirty bit of non-page.");
- data = (data & ~(1ul << 6)) | (v ? 1 << 6 : 0);
- }
- inline bool A() const {
- return (data & (1 << 5)) != 0;
- }
- inline void A(bool v) {
- data = (data & ~(1ul << 5)) | (v ? 1 << 5 : 0);
- }
- inline bool PCD() const {
- return (data & (1 << 4)) != 0;
- }
- inline void PCD(bool v) {
- data = (data & ~(1ul << 4)) | (v ? 1 << 4 : 0);
- }
- inline bool PWT() const {
- return (data & (1 << 3)) != 0;
- }
- inline void PWT(bool v) {
- data = (data & ~(1ul << 3)) | (v ? 1 << 3 : 0);
- }
- inline bool U_S() const {
- return (data & (1 << 2)) != 0;
- }
- inline void U_S(bool v) {
- data = (data & ~(1ul << 2)) | (v ? 1 << 2 : 0);
- }
- inline bool R_W() const {
- return (data & (1 << 1)) != 0;
- }
- inline void R_W(bool v) {
- data = (data & ~(1ul << 1)) | (v ? 1 << 1 : 0);
- }
- inline bool P() const {
- return (data & (1 << 0)) != 0;
- }
- inline void P(bool v) {
- data = (data & ~(1ul << 0)) | (v ? 1 << 0 : 0);
- }
-
-private:
- std::uint64_t data;
+struct PML4E;
+struct PML4T;
+union PDPE;
+struct PDPT;
+union PDE;
+struct PDT;
+struct PE;
+struct PT;
+struct page;
+
+struct __attribute__((packed)) PML4E {
+ std::uint64_t P : 1 = 0;
+ std::uint64_t R_W : 1;
+ std::uint64_t U_S : 1;
+ std::uint64_t PWT : 1;
+ std::uint64_t PCD : 1;
+ std::uint64_t A : 1 = 0;
+ std::uint64_t IGN : 1 = 0;
+ std::uint64_t MBZ : 2 = 0;
+ std::uint64_t AVL_low : 3 = 0;
+ std::uint64_t base_address : 40;
+ std::uint64_t AVL_high : 11 = 0;
+ std::uint64_t NX : 1;
};
-
-template <int order>
-struct __attribute__((aligned(0x1000))) paging_table {
- static_assert(order >= 0, "Paging table of negative order.");
- paging_entry<order> contents[512];
+static_assert(sizeof(PML4E) == 8);
+struct __attribute__((aligned(0x1000))) PML4T {
+ PML4E contents[512];
};
-static_assert(sizeof(paging_table<0>) == 0x1000);
-static_assert(alignof(paging_table<0>) == 0x1000);
+static_assert(sizeof(PML4T) == 0x1000);
+static_assert(alignof(PML4T) == 0x1000);
-template<>
-struct __attribute__((aligned(0x1000))) paging_table<-1> {
+struct __attribute__((aligned(0x1000))) page {
+ char contents[0x1000];
+};
+static_assert(sizeof(page) == 0x1000);
+static_assert(alignof(page) == 0x1000);
+
+union __attribute__((packed)) PDPE {
+ struct __attribute__((packed)) {
+ std::uint64_t P : 1 = 0;
+ std::uint64_t R_W : 1;
+ std::uint64_t U_S : 1;
+ std::uint64_t PWT : 1;
+ std::uint64_t PCD : 1;
+ std::uint64_t A : 1 = 0;
+ std::uint64_t IGN_0 : 1 = 0;
+ std::uint64_t zero : 1 = 0;
+ std::uint64_t IGN_1 : 1 = 0;
+ std::uint64_t AVL_low : 3 = 0;
+ std::uint64_t base_address : 40;
+ std::uint64_t AVL_high : 11 = 0;
+ std::uint64_t NX : 1;
+ } non_page;
+ struct __attribute__((packed)) {
+ std::uint64_t P : 1 = 0;
+ std::uint64_t R_W : 1;
+ std::uint64_t U_S : 1;
+ std::uint64_t PWT : 1;
+ std::uint64_t PCD : 1;
+ std::uint64_t A : 1 = 0;
+ std::uint64_t D : 1 = 0;
+ std::uint64_t one : 1 = 1;
+ std::uint64_t G : 1;
+ std::uint64_t AVL_low : 3 = 0;
+ std::uint64_t PAT : 1;
+ std::uint64_t reserved : 17 = 0;
+ std::uint64_t base_address : 22;
+ std::uint64_t AVL_high : 7 = 0;
+ std::uint64_t AVL_or_MPK : 4;
+ std::uint64_t NX : 1;
+ } page;
+};
+static_assert(sizeof(PDPE) == 8);
+struct __attribute__((aligned(0x1000))) PDPT {
+ PDPE contents[512];
+};
+static_assert(sizeof(PDPT) == 0x1000);
+static_assert(alignof(PDPT) == 0x1000);
+
+union __attribute__((packed)) PDE {
+ struct __attribute__((packed)) {
+ std::uint64_t P : 1 = 0;
+ std::uint64_t R_W : 1;
+ std::uint64_t U_S : 1;
+ std::uint64_t PWT : 1;
+ std::uint64_t PCD : 1;
+ std::uint64_t A : 1 = 0;
+ std::uint64_t IGN_0 : 1 = 0;
+ std::uint64_t zero : 1 = 0;
+ std::uint64_t IGN_1 : 1 = 0;
+ std::uint64_t AVL_low : 3 = 0;
+ std::uint64_t base_address : 40;
+ std::uint64_t AVL_high : 11 = 0;
+ std::uint64_t NX : 1;
+ } non_page;
+ struct __attribute__((packed)) {
+ std::uint64_t P : 1 = 0;
+ std::uint64_t R_W : 1;
+ std::uint64_t U_S : 1;
+ std::uint64_t PWT : 1;
+ std::uint64_t PCD : 1;
+ std::uint64_t A : 1 = 0;
+ std::uint64_t D : 1 = 0;
+ std::uint64_t one : 1 = 1;
+ std::uint64_t G : 1;
+ std::uint64_t AVL_low : 3 = 0;
+ std::uint64_t PAT : 1;
+ std::uint64_t reserved : 8 = 0;
+ std::uint64_t base_address : 31;
+ std::uint64_t AVL_high : 7 = 0;
+ std::uint64_t AVL_or_MPK : 4 = 0;
+ std::uint64_t NX : 1;
+ } page;
+};
+static_assert(sizeof(PDE) == 8);
+struct __attribute__((aligned(0x1000))) PDT {
+ PDE contents[512];
+};
+static_assert(sizeof(PDT) == 0x1000);
+static_assert(alignof(PDT) == 0x1000);
+
+struct __attribute__((packed)) PE {
+ std::uint64_t P : 1 = 0;
+ std::uint64_t R_W : 1;
+ std::uint64_t U_S : 1;
+ std::uint64_t PWT : 1;
+ std::uint64_t PCD : 1;
+ std::uint64_t A : 1 = 0;
+ std::uint64_t D : 1 = 0;
+ std::uint64_t PAT : 1;
+ std::uint64_t G : 1;
+ std::uint64_t AVL_low : 3 = 0;
+ std::uint64_t base_address : 40;
+ std::uint64_t AVL_high : 7 = 0;
+ std::uint64_t AVL_or_MPK : 4 = 0;
+ std::uint64_t NX : 1;
+};
+static_assert(sizeof(PE) == 8);
+struct __attribute__((aligned(0x1000))) PT {
+ PE contents[512];
};
-static_assert(sizeof(paging_table<-1>) == 0x1000);
-static_assert(alignof(paging_table<-1>) == 0x1000);
-
-using PML4T = paging_table<3>;
-using PML4E = paging_entry<3>;
-using PDPT = paging_table<2>;
-using PDPE = paging_entry<2>;
-using PDT = paging_table<1>;
-using PDE = paging_entry<1>;
-using PT = paging_table<0>;
-using PE = paging_entry<0>;
-using page = paging_table<-1>;
-
-void unmap(phys_ptr<PML4T> PLM4T, page* virt, std::uint64_t length);
-void map(phys_ptr<PML4T> PLM4T, page* virt, std::uint64_t length, phys_ptr<page> phys);
-void print_mapping(const PML4T& PML4T, bool show_higher_half = false);
+static_assert(sizeof(PT) == 0x1000);
+static_assert(alignof(PT) == 0x1000);
+
+
+inline bool is_page(const PML4E __attribute__((unused))& PML4E) { return false; }
+inline bool is_page(const PDPE& PDPE) { return PDPE.page.one == 1; }
+inline bool is_page(const PDE& PDE) { return PDE.page.one == 1; }
+inline bool is_page(const PE __attribute__((unused))& PE) { return true; }
+
+inline phys_ptr<PDPT> get_base_address(const PML4E& PML4E) {
+ os::assert(!is_page(PML4E), "Tried to get non-page out of a page paging.");
+ return phys_ptr<PDPT>{PML4E.base_address * 0x1000ull};
+}
+inline phys_ptr<PDT> get_base_address(const PDPE& PDPE) {
+ os::assert(!is_page(PDPE), "Tried to get non-page out of a page paging.");
+ return phys_ptr<PDT>{PDPE.non_page.base_address * 0x1000ull};
+}
+inline phys_ptr<PT> get_base_address(const PDE& PDE) {
+ os::assert(!is_page(PDE), "Tried to get non-page out of a page paging.");
+ return phys_ptr<PT>{PDE.non_page.base_address * 0x1000ull};
+}
+inline phys_ptr<page> get_page_base_address(const PDPE& PDPE) {
+ os::assert(is_page(PDPE), "Tried to get page out of a non-page paging.");
+ return phys_ptr<page>{PDPE.page.base_address * 0x1000ull * 512ull * 512ull};
+}
+inline phys_ptr<page> get_page_base_address(const PDE& PDE) {
+ os::assert(is_page(PDE), "Tried to get page out of a non-page paging.");
+ return phys_ptr<page>{PDE.page.base_address * 0x1000ull * 512ull};
+}
+inline phys_ptr<page> get_page_base_address(const PE& PE) {
+ os::assert(is_page(PE), "Tried to get page out of a non-page paging.");
+ return phys_ptr<page>{PE.base_address * 0x1000ull};
+}
+
+inline void set_base_address(PML4E& PML4E, phys_ptr<PDPT> ptr) {
+ os::assert(!is_page(PML4E), "Tried to get non-page out of a page paging.");
+ PML4E.base_address = ptr.get_phys_addr() / 0x1000ull;
+}
+inline void set_base_address(PDPE& PDPE, phys_ptr<PDT> ptr) {
+ os::assert(!is_page(PDPE), "Tried to get non-page out of a page paging.");
+ PDPE.non_page.base_address = ptr.get_phys_addr() / 0x1000ull;
+}
+inline void set_base_address(PDE& PDE, phys_ptr<PT> ptr) {
+ os::assert(!is_page(PDE), "Tried to get non-page out of a page paging.");
+ PDE.non_page.base_address = ptr.get_phys_addr() / 0x1000ull;
+}
+inline void set_page_base_address(PDPE& PDPE, phys_ptr<page> ptr) {
+ os::assert(is_page(PDPE), "Tried to get page out of a non-page paging.");
+ PDPE.page.base_address = ptr.get_phys_addr() / 0x1000ull / 512ull / 512ull;
+}
+inline void set_page_base_address(PDE& PDE, phys_ptr<page> ptr) {
+ os::assert(is_page(PDE), "Tried to get page out of a non-page paging.");
+ PDE.page.base_address = ptr.get_phys_addr() / 0x1000ull / 512ull;
+}
+inline void set_page_base_address(PE& PE, phys_ptr<page> ptr) {
+ os::assert(is_page(PE), "Tried to get page out of a non-page paging.");
+ PE.base_address = ptr.get_phys_addr() / 0x1000ull;
+}
+
+// For all present page mappings, calls f(virtual address, physical address, page size in bytes (4KiB, 2MiB or 1GiB)).
+void on_all_pages(const PML4T& PML4T, void f(page*, phys_ptr<page>, std::size_t));
class page_allocator_t;
extern page_allocator_t page_allocator;