195 lines
4.4 KiB
D
195 lines
4.4 KiB
D
/**
|
|
* 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_PAT = 0x80u; /* Page table entry bit. */
|
|
enum ulong PT_HUGE_PAGE = 0x80u; /* Page directory entry bit. */
|
|
enum ulong PT_GLOBAL = 0x100u;
|
|
enum ulong PT_NO_EXECUTE = 0x8000_0000_0000_0000u;
|
|
/** @} */
|
|
|
|
/** Page size in bytes. */
|
|
enum ulong PAGE_SIZE = 4096u;
|
|
|
|
/**
|
|
* Structure that represents a page table entry.
|
|
*/
|
|
struct PageTableEntry
|
|
{
|
|
/** The raw page table entry is a 64-bit ulong. */
|
|
public 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;
|
|
}
|
|
|
|
/**
|
|
* Return whether the page is dirty.
|
|
*/
|
|
public @property bool dirty() const
|
|
{
|
|
return (entry & PT_DIRTY) != 0u;
|
|
}
|
|
|
|
/**
|
|
* Return whether the page is accessed.
|
|
*/
|
|
public @property bool accessed() const
|
|
{
|
|
return (entry & PT_ACCESSED) != 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
|
|
{
|
|
/** Number of page table entries in a page table. */
|
|
enum size_t N_ENTRIES = 512u;
|
|
|
|
/** Page table entries. */
|
|
private PageTableEntry[N_ENTRIES] 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;
|
|
}
|
|
|
|
/**
|
|
* Access a page table entry by linear index.
|
|
*
|
|
* @param index
|
|
* Page table index (0-511).
|
|
*
|
|
* @return PageTableEntry at the given index.
|
|
*/
|
|
public PageTableEntry opIndex(size_t index)
|
|
{
|
|
return entries[index];
|
|
}
|
|
}
|
|
static assert(PageTable.sizeof == 4096u);
|
|
|
|
/**
|
|
* Get the base address of the page containing the given address.
|
|
*/
|
|
T page_address(T)(T address)
|
|
{
|
|
return cast(T)(cast(ulong)address & ~(PAGE_SIZE - 1u));
|
|
}
|