Add Hurl struct with map() method

This commit is contained in:
Josh Holtrop 2022-05-01 09:26:33 -04:00
parent 7515ebdf1c
commit 89f7d2120f

View File

@ -5,6 +5,10 @@
*/ */
module hulk.hurl; module hulk.hurl;
import hos.cpu;
import hulk.hippo;
import hos.memory;
/** HULK virtual base address. */ /** HULK virtual base address. */
enum ulong HULK_VIRTUAL_BASE_ADDRESS = 0xFFFF_8000_0000_0000u; enum ulong HULK_VIRTUAL_BASE_ADDRESS = 0xFFFF_8000_0000_0000u;
@ -13,3 +17,108 @@ 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
{
private struct PageTableEntry
{
private ulong m_entry;
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);
}
private ulong pt_index(ulong address, ulong level)
{
return (address >> (39u - (9u * level))) & 0x1FFu;
}
}
private static __gshared PageTable * m_pt_base;
public static void initialize()
{
m_pt_base = cast(PageTable *)read_cr3();
}
public static void map(ulong virtual, ulong physical, ulong flags)
{
size_t last_level = ((flags & MAP_HUGE_PAGE) != 0u) ? 2u : 3u;
PageTable * pt = m_pt_base;
for (size_t level = 0; level <= last_level; level++)
{
if (level < last_level)
{
PageTableEntry entry = (*pt)[virtual, level];
if (entry.present)
{
pt = entry.follow();
}
else
{
PageTable * next_pt = cast(PageTable *)hippo.allocate_page();
memset32(next_pt, 0, 4096u / 4u);
(*pt)[virtual, level] = PageTableEntry(next_pt, MAP_WRITABLE | MAP_PRESENT);
pt = next_pt;
}
}
else
{
(*pt)[virtual, level] = PageTableEntry(physical, flags | MAP_PRESENT);
}
}
}
}