/** * HURL, the HOS Unreal Region Locator. * * HURL provides virtual memory management for HULK. */ module hulk.hurl; import hos.cpu; import hulk.hippo; import hos.memory; /** HULK virtual base address. */ enum ulong HULK_VIRTUAL_BASE_ADDRESS = 0xFFFF_8000_0000_0000u; /** HULK virtual stack top address. */ 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; 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); } } } public static void map_range(size_t address, size_t length, ulong flags) { size_t end = address + length; for (size_t page = address & ~0xFFFu; page < end; page += 0x1000u) { map(address, address, flags); } } }