From 555ec9b627c605ca410e3f2930c913753cf4c35e Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 25 Oct 2022 23:30:17 -0400 Subject: [PATCH] Split PageTable struct out from hulk.hurl to hulk.pagetable --- src/hulk/apic.d | 2 +- src/hulk/hurl.d | 85 +++------------------- src/hulk/pagetable.d | 164 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 77 deletions(-) create mode 100644 src/hulk/pagetable.d diff --git a/src/hulk/apic.d b/src/hulk/apic.d index 74102dc..e8e6a9f 100644 --- a/src/hulk/apic.d +++ b/src/hulk/apic.d @@ -62,7 +62,7 @@ struct apic ApicRegisters * apic_registers = cast(ApicRegisters *)acpi.apic_address; hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers, - MAP_WRITABLE | MAP_WRITE_THROUGH | MAP_DISABLE_CACHE | MAP_NO_EXECUTE); + PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE); klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.read()); klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.read()); } diff --git a/src/hulk/hurl.d b/src/hulk/hurl.d index 057c1e2..c3aac5e 100644 --- a/src/hulk/hurl.d +++ b/src/hulk/hurl.d @@ -5,6 +5,7 @@ */ module hulk.hurl; +public import hulk.pagetable; import hos.cpu; import hulk.hippo; import hos.memory; @@ -21,76 +22,8 @@ enum ulong HULK_VIRTUAL_STACK_TOP_ADDRESS = 0xFFFF_A000_0000_0000u; /** HULK virtual framebuffer address. */ enum ulong HULK_VIRTUAL_FRAMEBUFFER_ADDRESS = 0xFFFF_A000_0000_0000u; -/** Page table entry attributes. @{ */ -enum ulong MAP_PRESENT = 0x1u; -enum ulong MAP_WRITABLE = 0x2u; -enum ulong MAP_USER = 0x4u; -enum ulong MAP_WRITE_THROUGH = 0x8u; -enum ulong MAP_DISABLE_CACHE = 0x10u; -enum ulong MAP_HUGE_PAGE = 0x20u; -enum ulong MAP_GLOBAL = 0x40u; -enum ulong MAP_NO_EXECUTE = 0x8000_0000_0000_0000u; -/** @} */ - struct hurl { - private struct PageTableEntry - { - private ulong m_entry; - alias m_entry this; - - this(ulong address, ulong flags) - { - m_entry = address | flags; - } - - this(void * address, ulong flags) - { - m_entry = cast(ulong)address | flags; - } - - public @property bool present() - { - return (m_entry & MAP_PRESENT) != 0u; - } - - public PageTable * follow() - { - return cast(PageTable *)(m_entry & 0x7FFF_FFFF_FFFF_F000u); - } - } - - private struct PageTable - { - public PageTableEntry opIndex(ulong address, ulong level) - { - PageTableEntry * entries = cast(PageTableEntry *)&this; - return entries[pt_index(address, level)]; - } - - public PageTableEntry opIndex(void * address, ulong level) - { - return opIndex(cast(ulong)address, level); - } - - public PageTableEntry opIndexAssign(PageTableEntry pte, ulong address, ulong level) - { - PageTableEntry * entries = cast(PageTableEntry *)&this; - entries[pt_index(address, level)] = pte; - return pte; - } - - public PageTableEntry opIndexAssign(PageTableEntry pte, void * address, ulong level) - { - return opIndexAssign(pte, cast(ulong)address, level); - } - - public ulong pt_index(ulong address, ulong level) - { - return (address >> (39u - (9u * level))) & 0x1FFu; - } - } - private static __gshared PageTable * m_pt_base; /** @@ -106,27 +39,27 @@ struct hurl map_range(0u, 0u, hippo.physical_address_limit, - MAP_WRITABLE | MAP_NO_EXECUTE); + PT_WRITABLE | PT_NO_EXECUTE); /* Map HULK binary region. */ map_range(HULK_VIRTUAL_BASE_ADDRESS, header.bootinfo.hulk_phys, hulk_bin_phys_size, - MAP_WRITABLE); + PT_WRITABLE); /* Map HULK BSS region. */ map_range(HULK_VIRTUAL_BASE_ADDRESS + hulk_bin_phys_size, header.bootinfo.bss_phys, LinkerAddresses.hulk_bss_size, - MAP_WRITABLE | MAP_NO_EXECUTE); + PT_WRITABLE | PT_NO_EXECUTE); /* Map HULK stack. */ map_range(HULK_VIRTUAL_STACK_TOP_ADDRESS - header.stack_size, header.bootinfo.stack_phys, header.stack_size, - MAP_WRITABLE | MAP_NO_EXECUTE); + PT_WRITABLE | PT_NO_EXECUTE); /* Map HULK framebuffer. */ map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, cast(ulong)header.bootinfo.fb.buffer, header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, - MAP_WRITABLE | MAP_NO_EXECUTE); + PT_WRITABLE | PT_NO_EXECUTE); write_cr3(cast(ulong)m_pt_base); } @@ -145,13 +78,13 @@ struct hurl else { PageTable * next_pt = allocate_pt(); - (*pt)[virtual, level] = PageTableEntry(next_pt, MAP_WRITABLE | MAP_PRESENT); + (*pt)[virtual, level] = PageTableEntry(next_pt, PT_WRITABLE | PT_PRESENT); pt = next_pt; } } else { - (*pt)[virtual, level] = PageTableEntry(physical, flags | MAP_PRESENT); + (*pt)[virtual, level] = PageTableEntry(physical, flags | PT_PRESENT); } } } @@ -192,7 +125,7 @@ struct hurl { break; } - if ((entry & MAP_HUGE_PAGE) != 0u) + if (entry.huge) { break; } diff --git a/src/hulk/pagetable.d b/src/hulk/pagetable.d new file mode 100644 index 0000000..e1263e4 --- /dev/null +++ b/src/hulk/pagetable.d @@ -0,0 +1,164 @@ +/** + * Page table structures. + */ +module hulk.pagetable; + +/** Page table entry attributes. @{ */ +enum ulong PT_PRESENT = 0x1u; +enum ulong PT_WRITABLE = 0x2u; +enum ulong PT_USER = 0x4u; +enum ulong PT_WRITE_THROUGH = 0x8u; +enum ulong PT_DISABLE_CACHE = 0x10u; +enum ulong PT_HUGE_PAGE = 0x80u; +enum ulong PT_GLOBAL = 0x100u; +enum ulong PT_NO_EXECUTE = 0x8000_0000_0000_0000u; +/** @} */ + +/** + * Structure that represents a page table entry. + */ +struct PageTableEntry +{ + /** The raw page table entry is a 64-bit ulong. */ + private ulong entry; + alias entry this; + + /** + * Construct a page table entry. + * + * @param address + * Address pointed to by the page table entry (ulong or pointer). + * @param flags + * Page table flags (ORed set of PT_*). + */ + this(T)(T address, ulong flags = 0u) + { + entry = cast(ulong)address | flags; + } + + /** + * Return whether the page is present. + */ + public @property bool present() const + { + return (entry & PT_PRESENT) != 0u; + } + + /** + * Return whether the page is writable. + */ + public @property bool writable() const + { + return (entry & PT_WRITABLE) != 0u; + } + + /** + * Return whether the page is a user page. + */ + public @property bool user() const + { + return (entry & PT_USER) != 0u; + } + + /** + * Return whether the page is write-through. + */ + public @property bool write_through() const + { + return (entry & PT_WRITE_THROUGH) != 0u; + } + + /** + * Return whether the page has disable cache set. + */ + public @property bool disable_cache() const + { + return (entry & PT_DISABLE_CACHE) != 0u; + } + + /** + * Return whether the page is huge. + */ + public @property bool huge() const + { + return (entry & PT_HUGE_PAGE) != 0u; + } + + /** + * Return whether the page is global. + */ + public @property bool global() const + { + return (entry & PT_GLOBAL) != 0u; + } + + /** + * Return whether the page is no-execute. + */ + public @property bool no_execute() const + { + return (entry & PT_NO_EXECUTE) != 0u; + } + + /** + * Follow the page table entry to the next page table it points to. + */ + public PageTable * follow() const + { + return cast(PageTable *)(entry & 0x7FFF_FFFF_FFFF_F000u); + } +} +static assert(PageTableEntry.sizeof == 8u); + +/** + * Structure that represents a page table. + */ +struct PageTable +{ + /** Page table entries. */ + private PageTableEntry[512] entries; + + /** + * Access the PageTableEntry for the given address and page table level. + * + * @param address + * Address to look up the page table entry (ulong or pointer). + * @param level + * Page table level (0-4). + */ + public PageTableEntry opIndex(T)(T address, ulong level) + { + return entries[pt_index(cast(ulong)address, level)]; + } + + /** + * Assign the PageTableEntry for the given address and page table level. + * + * @param pte + * PageTableEntry value to assign. + * @param address + * Address to look up the page table entry (ulong or pointer). + * @param level + * Page table level (0-4). + */ + public PageTableEntry opIndexAssign(T)(PageTableEntry pte, T address, ulong level) + { + entries[pt_index(cast(ulong)address, level)] = pte; + return pte; + } + + /** + * Determine the index into the page table for the given address and page + * table level. + * + * @param address + * Address to look up the page table entry (ulong or pointer). + * @param level + * Page table level (0-4). + */ + public ulong pt_index(T)(T address, ulong level) + { + return (cast(ulong)address >> (39u - (9u * level))) & 0x1FFu; + } +} +static assert(PageTable.sizeof == 4096u);