/** * 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_ACCESSED = 0x20u; enum ulong PT_DIRTY = 0x40u; 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 * entry(T)(T address, ulong level) { return &entries[index(cast(ulong)address, level)]; } /** * 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 index(T)(T address, ulong level) { return (cast(ulong)address >> (39u - (9u * level))) & 0x1FFu; } } static assert(PageTable.sizeof == 4096u);