Split PageTable struct out from hulk.hurl to hulk.pagetable

This commit is contained in:
Josh Holtrop 2022-10-25 23:30:17 -04:00
parent c11361d40f
commit 555ec9b627
3 changed files with 174 additions and 77 deletions

View File

@ -62,7 +62,7 @@ struct apic
ApicRegisters * apic_registers = ApicRegisters * apic_registers =
cast(ApicRegisters *)acpi.apic_address; cast(ApicRegisters *)acpi.apic_address;
hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers, 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 ID: 0x%08x", apic_registers.lapic_id.read());
klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.read()); klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.read());
} }

View File

@ -5,6 +5,7 @@
*/ */
module hulk.hurl; module hulk.hurl;
public import hulk.pagetable;
import hos.cpu; import hos.cpu;
import hulk.hippo; import hulk.hippo;
import hos.memory; import hos.memory;
@ -21,76 +22,8 @@ enum ulong HULK_VIRTUAL_STACK_TOP_ADDRESS = 0xFFFF_A000_0000_0000u;
/** HULK virtual framebuffer address. */ /** HULK virtual framebuffer address. */
enum ulong HULK_VIRTUAL_FRAMEBUFFER_ADDRESS = 0xFFFF_A000_0000_0000u; 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 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; private static __gshared PageTable * m_pt_base;
/** /**
@ -106,27 +39,27 @@ struct hurl
map_range(0u, map_range(0u,
0u, 0u,
hippo.physical_address_limit, hippo.physical_address_limit,
MAP_WRITABLE | MAP_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK binary region. */ /* Map HULK binary region. */
map_range(HULK_VIRTUAL_BASE_ADDRESS, map_range(HULK_VIRTUAL_BASE_ADDRESS,
header.bootinfo.hulk_phys, header.bootinfo.hulk_phys,
hulk_bin_phys_size, hulk_bin_phys_size,
MAP_WRITABLE); PT_WRITABLE);
/* Map HULK BSS region. */ /* Map HULK BSS region. */
map_range(HULK_VIRTUAL_BASE_ADDRESS + hulk_bin_phys_size, map_range(HULK_VIRTUAL_BASE_ADDRESS + hulk_bin_phys_size,
header.bootinfo.bss_phys, header.bootinfo.bss_phys,
LinkerAddresses.hulk_bss_size, LinkerAddresses.hulk_bss_size,
MAP_WRITABLE | MAP_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK stack. */ /* Map HULK stack. */
map_range(HULK_VIRTUAL_STACK_TOP_ADDRESS - header.stack_size, map_range(HULK_VIRTUAL_STACK_TOP_ADDRESS - header.stack_size,
header.bootinfo.stack_phys, header.bootinfo.stack_phys,
header.stack_size, header.stack_size,
MAP_WRITABLE | MAP_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK framebuffer. */ /* Map HULK framebuffer. */
map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(ulong)header.bootinfo.fb.buffer, cast(ulong)header.bootinfo.fb.buffer,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, 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); write_cr3(cast(ulong)m_pt_base);
} }
@ -145,13 +78,13 @@ struct hurl
else else
{ {
PageTable * next_pt = allocate_pt(); 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; pt = next_pt;
} }
} }
else else
{ {
(*pt)[virtual, level] = PageTableEntry(physical, flags | MAP_PRESENT); (*pt)[virtual, level] = PageTableEntry(physical, flags | PT_PRESENT);
} }
} }
} }
@ -192,7 +125,7 @@ struct hurl
{ {
break; break;
} }
if ((entry & MAP_HUGE_PAGE) != 0u) if (entry.huge)
{ {
break; break;
} }

164
src/hulk/pagetable.d Normal file
View File

@ -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);