Build HELLO page tables from unused memory instead of scratch buffer

This commit is contained in:
Josh Holtrop 2022-11-02 22:49:42 -04:00
parent 0b326e2e36
commit 8aa01ba122
4 changed files with 99 additions and 75 deletions

View File

@ -5,7 +5,6 @@ module hello.hello;
import uefi; import uefi;
import hello.console; import hello.console;
import hello.scratch;
import hulk.bootinfo; import hulk.bootinfo;
import hulk.header; import hulk.header;
import hulk.pagetable; import hulk.pagetable;
@ -16,6 +15,9 @@ import ldc.llvmasm;
__gshared EFI_SYSTEM_TABLE * st; __gshared EFI_SYSTEM_TABLE * st;
extern extern(C) __gshared ubyte _hulk_bin_start; extern extern(C) __gshared ubyte _hulk_bin_start;
extern extern(C) __gshared ubyte _hulk_bin_end; extern extern(C) __gshared ubyte _hulk_bin_end;
private align(4096) __gshared ubyte[1024 * 1024] scratch_buffer;
/** Index to the memory map region being used to allocate page tables. */
private __gshared size_t memory_map_page_table_alloc_index;
private HulkHeader * hulk_header() private HulkHeader * hulk_header()
{ {
@ -87,9 +89,9 @@ private bool in_qemu()
private bool set_graphics_mode() private bool set_graphics_mode()
{ {
uint max_horizontal_resolution = in_qemu() ? 1920u : 0xFFFFFFFFu; uint max_horizontal_resolution = in_qemu() ? 1920u : 0xFFFFFFFFu;
UINTN buffer_size = scratch.free(); UINTN buffer_size = scratch_buffer.sizeof;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_HANDLE * handles = cast(EFI_HANDLE *)scratch.current(); EFI_HANDLE * handles = cast(EFI_HANDLE *)&scratch_buffer[0];
EFI_STATUS status = st.BootServices.LocateHandle(ByProtocol, EFI_STATUS status = st.BootServices.LocateHandle(ByProtocol,
&gop_guid, null, &buffer_size, handles); &gop_guid, null, &buffer_size, handles);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
@ -148,10 +150,10 @@ private void get_memory_map(ulong * bss_phys, ulong * stack_phys, ulong * physic
{ {
immutable static ubyte[] efi_to_hulk_memory_map_type = [ immutable static ubyte[] efi_to_hulk_memory_map_type = [
BootInfo.MemoryRegion.Type.Reserved, // EfiReservedMemoryType BootInfo.MemoryRegion.Type.Reserved, // EfiReservedMemoryType
BootInfo.MemoryRegion.Type.Conventional, // EfiLoaderCode BootInfo.MemoryRegion.Type.Bootloader, // EfiLoaderCode
BootInfo.MemoryRegion.Type.Conventional, // EfiLoaderData BootInfo.MemoryRegion.Type.Bootloader, // EfiLoaderData
BootInfo.MemoryRegion.Type.Conventional, // EfiBootServicesCode BootInfo.MemoryRegion.Type.Bootloader, // EfiBootServicesCode
BootInfo.MemoryRegion.Type.Conventional, // EfiBootServicesData BootInfo.MemoryRegion.Type.Bootloader, // EfiBootServicesData
BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesCode BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesCode
BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesData BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesData
BootInfo.MemoryRegion.Type.Conventional, // EfiConventionalMemory BootInfo.MemoryRegion.Type.Conventional, // EfiConventionalMemory
@ -163,10 +165,10 @@ private void get_memory_map(ulong * bss_phys, ulong * stack_phys, ulong * physic
BootInfo.MemoryRegion.Type.PalCode, // EfiPalCode BootInfo.MemoryRegion.Type.PalCode, // EfiPalCode
]; ];
*physical_address_limit = 0u; *physical_address_limit = 0u;
UINTN memory_map_size = scratch.free(); UINTN memory_map_size = scratch_buffer.sizeof;
UINTN descriptor_size; UINTN descriptor_size;
UINT32 descriptor_version; UINT32 descriptor_version;
ubyte * scratch_base = scratch.current(); ubyte * scratch_base = cast(ubyte *)&scratch_buffer[0];
UINTN status = st.BootServices.GetMemoryMap( UINTN status = st.BootServices.GetMemoryMap(
&memory_map_size, &memory_map_size,
cast(EFI_MEMORY_DESCRIPTOR *)scratch_base, cast(EFI_MEMORY_DESCRIPTOR *)scratch_base,
@ -235,12 +237,37 @@ private void get_memory_map(ulong * bss_phys, ulong * stack_phys, ulong * physic
} }
} }
private void * alloc_pt_page()
{
BootInfo.MemoryRegion * regions = &bootinfo().memory_map[0];
for (;;)
{
BootInfo.MemoryRegion * region = &bootinfo().memory_map[memory_map_page_table_alloc_index];
if ((region.type == BootInfo.MemoryRegion.Type.Conventional) && (region.size >= PAGE_SIZE))
{
void * addr = cast(void *)region.base;
region.base += PAGE_SIZE;
region.size -= PAGE_SIZE;
return addr;
}
memory_map_page_table_alloc_index++;
if (memory_map_page_table_alloc_index >= bootinfo().memory_map_count)
{
return null;
}
}
}
/** /**
* Allocate a new page table. * Allocate a new page table.
*/ */
private PageTable * new_page_table() private PageTable * new_page_table()
{ {
PageTable * pt = cast(PageTable *)scratch.alloc(1u); PageTable * pt = cast(PageTable *)alloc_pt_page();
if (pt == null)
{
return null;
}
memset64(pt, 0u, 512); memset64(pt, 0u, 512);
return pt; return pt;
} }
@ -252,7 +279,7 @@ private PageTable * new_page_table()
* @param dest_page Destination page address. * @param dest_page Destination page address.
* @param pt_base Page table base address. * @param pt_base Page table base address.
*/ */
private void map4k(ulong source_page, ulong dest_page, PageTable * pt_base) private bool map4k(ulong source_page, ulong dest_page, PageTable * pt_base)
{ {
PageTable * pt = pt_base; PageTable * pt = pt_base;
for (size_t level = 0; level < 4u; level++) for (size_t level = 0; level < 4u; level++)
@ -270,6 +297,10 @@ private void map4k(ulong source_page, ulong dest_page, PageTable * pt_base)
if (level < 3u) if (level < 3u)
{ {
next_pt = new_page_table(); next_pt = new_page_table();
if (next_pt == null)
{
return false;
}
addr = cast(ulong)next_pt; addr = cast(ulong)next_pt;
} }
else else
@ -280,6 +311,7 @@ private void map4k(ulong source_page, ulong dest_page, PageTable * pt_base)
pt = next_pt; pt = next_pt;
} }
} }
return true;
} }
/** /**
@ -290,15 +322,19 @@ private void map4k(ulong source_page, ulong dest_page, PageTable * pt_base)
* @param size Region size. * @param size Region size.
* @param pt_base Page table base address. * @param pt_base Page table base address.
*/ */
private void map4kregion(ulong source, ulong dest, size_t size, PageTable * pt_base) private bool map4kregion(ulong source, ulong dest, size_t size, PageTable * pt_base)
{ {
ulong end = source + size; ulong end = source + size;
while (source < end) while (source < end)
{ {
map4k(source, dest, pt_base); if (!map4k(source, dest, pt_base))
{
return false;
}
source += 4096u; source += 4096u;
dest += 4096u; dest += 4096u;
} }
return true;
} }
/** /**
@ -308,7 +344,7 @@ private void map4kregion(ulong source, ulong dest, size_t size, PageTable * pt_b
* @param dest_page Destination page address. * @param dest_page Destination page address.
* @param pt_base Page table base address. * @param pt_base Page table base address.
*/ */
private void map2m(ulong source_page, ulong dest_page, PageTable * pt_base) private bool map2m(ulong source_page, ulong dest_page, PageTable * pt_base)
{ {
PageTable * pt = pt_base; PageTable * pt = pt_base;
for (size_t level = 0; level < 3u; level++) for (size_t level = 0; level < 3u; level++)
@ -325,6 +361,10 @@ private void map2m(ulong source_page, ulong dest_page, PageTable * pt_base)
if (level < 2u) if (level < 2u)
{ {
next_pt = new_page_table(); next_pt = new_page_table();
if (next_pt == null)
{
return false;
}
*ppte = PageTableEntry(next_pt, PT_WRITABLE | PT_PRESENT); *ppte = PageTableEntry(next_pt, PT_WRITABLE | PT_PRESENT);
} }
else else
@ -334,6 +374,7 @@ private void map2m(ulong source_page, ulong dest_page, PageTable * pt_base)
pt = next_pt; pt = next_pt;
} }
} }
return true;
} }
/** /**
@ -341,17 +382,27 @@ private void map2m(ulong source_page, ulong dest_page, PageTable * pt_base)
* *
* @param pt_base Page table base address. * @param pt_base Page table base address.
*/ */
private void map_hulk(PageTable * pt_base, ulong bss_phys, ulong stack_phys) private bool map_hulk(PageTable * pt_base, ulong bss_phys, ulong stack_phys)
{ {
/* Map HULK bin region. */ /* Map HULK bin region. */
ulong virt = hulk_virt_base_address(); ulong virt = hulk_virt_base_address();
map4kregion(virt, hulk_bin_phys(), hulk_bin_size(), pt_base); if (!map4kregion(virt, hulk_bin_phys(), hulk_bin_size(), pt_base))
{
return false;
}
/* Map HULK bss region. */ /* Map HULK bss region. */
virt += hulk_bin_size(); virt += hulk_bin_size();
map4kregion(virt, bss_phys, hulk_bss_size(), pt_base); if (!map4kregion(virt, bss_phys, hulk_bss_size(), pt_base))
{
return false;
}
/* Map HULK stack. */ /* Map HULK stack. */
virt = hulk_virt_stack_top() - hulk_stack_size(); virt = hulk_virt_stack_top() - hulk_stack_size();
map4kregion(virt, stack_phys, hulk_stack_size(), pt_base); if (!map4kregion(virt, stack_phys, hulk_stack_size(), pt_base))
{
return false;
}
return true;
} }
/** /**
@ -359,13 +410,20 @@ private void map_hulk(PageTable * pt_base, ulong bss_phys, ulong stack_phys)
* *
* @param physical_address_limit Maximum physical address to identity map. * @param physical_address_limit Maximum physical address to identity map.
*/ */
private void build_page_tables(ulong physical_address_limit, ulong bss_phys, ulong stack_phys) private bool build_page_tables(ulong physical_address_limit, ulong bss_phys, ulong stack_phys)
{ {
PageTable * pt_base = new_page_table(); PageTable * pt_base = new_page_table();
if (pt_base == null)
{
return false;
}
/* Map physical RAM. */ /* Map physical RAM. */
for (size_t addr = 0u; addr < physical_address_limit; addr += (2u * 1024u * 1024u)) for (size_t addr = 0u; addr < physical_address_limit; addr += (2u * 1024u * 1024u))
{ {
map2m(addr, addr, pt_base); if (!map2m(addr, addr, pt_base))
{
return false;
}
} }
/* Map any memory regions that are outside physical RAM. */ /* Map any memory regions that are outside physical RAM. */
for (size_t i = 0u; i < bootinfo().memory_map_count; i++) for (size_t i = 0u; i < bootinfo().memory_map_count; i++)
@ -373,18 +431,28 @@ private void build_page_tables(ulong physical_address_limit, ulong bss_phys, ulo
ulong addr = bootinfo().memory_map[i].base; ulong addr = bootinfo().memory_map[i].base;
if (addr >= physical_address_limit) if (addr >= physical_address_limit)
{ {
map4kregion(addr, addr, bootinfo().memory_map[i].size, pt_base); if (!map4kregion(addr, addr, bootinfo().memory_map[i].size, pt_base))
{
return false;
}
} }
} }
/* Map graphics framebuffer. */ /* Map graphics framebuffer. */
ulong framebuffer_size = bootinfo().fb.height * bootinfo().fb.stride * 4u; ulong framebuffer_size = bootinfo().fb.height * bootinfo().fb.stride * 4u;
ulong fb_phys = cast(ulong)bootinfo().fb.buffer; ulong fb_phys = cast(ulong)bootinfo().fb.buffer;
ulong fb_virt = hulk_virt_framebuffer_address(); ulong fb_virt = hulk_virt_framebuffer_address();
map4kregion(fb_virt, fb_phys, framebuffer_size, pt_base); if (!map4kregion(fb_virt, fb_phys, framebuffer_size, pt_base))
{
return false;
}
/* Map HULK regions. */ /* Map HULK regions. */
map_hulk(pt_base, bss_phys, stack_phys); if (!map_hulk(pt_base, bss_phys, stack_phys))
{
return false;
}
/* Switch to the new page table. */ /* Switch to the new page table. */
write_cr3(cast(ulong)pt_base); write_cr3(cast(ulong)pt_base);
return true;
} }
/** /**
@ -447,8 +515,6 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
bootinfo().pt_phys = cast(ulong)scratch.current();
if (!set_graphics_mode()) if (!set_graphics_mode())
{ {
console.wait_key(); console.wait_key();
@ -477,12 +543,14 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
build_page_tables(physical_address_limit, bss_phys, stack_phys); if (!build_page_tables(physical_address_limit, bss_phys, stack_phys))
{
return EFI_SUCCESS;
}
bootinfo().hulk_phys = hulk_bin_phys(); bootinfo().hulk_phys = hulk_bin_phys();
bootinfo().bss_phys = bss_phys; bootinfo().bss_phys = bss_phys;
bootinfo().stack_phys = stack_phys; bootinfo().stack_phys = stack_phys;
bootinfo().pt_size = cast(ulong)scratch.current() - bootinfo().pt_phys;
jump_to_hulk(); jump_to_hulk();

View File

@ -1,39 +0,0 @@
/**
* HELLO scratch buffer.
*/
module hello.scratch;
struct scratch
{
/* Scratch buffer. */
private static align(4096) __gshared ubyte[10 * 1024 * 1024] scratch;
/* Number of scratch buffer bytes used. */
private static __gshared size_t scratch_used;
/**
* Get the number of free bytes in the scratch buffer.
*/
public static size_t free()
{
return scratch.sizeof - scratch_used;
}
/**
* Get the current free scratch buffer address.
*/
public static ubyte * current()
{
return &scratch[scratch_used];
}
/**
* Allocate pages from the scratch buffer.
*/
public static ubyte * alloc(size_t n = 1)
{
ubyte * address = &scratch[scratch_used];
scratch_used += 4096u * n;
return address;
}
}

View File

@ -33,6 +33,7 @@ struct BootInfo
enum Type enum Type
{ {
Reserved, Reserved,
Bootloader,
Conventional, Conventional,
Unusable, Unusable,
ACPIReclaim, ACPIReclaim,
@ -68,12 +69,6 @@ struct BootInfo
/* Physical address of stack while jumping to HULK. */ /* Physical address of stack while jumping to HULK. */
ulong stack_phys; ulong stack_phys;
/* Physical address of page tables while jumping to HULK. */
ulong pt_phys;
/* Size of page tables while jumping to HULK. */
ulong pt_size;
/* Physical address of ACPI XSDT table. */ /* Physical address of ACPI XSDT table. */
ulong acpi_xsdt_phys; ulong acpi_xsdt_phys;
} }

View File

@ -53,12 +53,11 @@ struct hippo
public static void initialize(HulkHeader * header) public static void initialize(HulkHeader * header)
{ {
size_t usable_memory; size_t usable_memory;
ulong[2][5] reserved = [ ulong[2][4] reserved = [
[header.bootinfo.hulk_phys, cast(ulong)header.total_size - LinkerAddresses.hulk_bss_size], [header.bootinfo.hulk_phys, cast(ulong)header.total_size - LinkerAddresses.hulk_bss_size],
[header.bootinfo.bss_phys, LinkerAddresses.hulk_bss_size], [header.bootinfo.bss_phys, LinkerAddresses.hulk_bss_size],
[header.bootinfo.stack_phys, header.stack_size], [header.bootinfo.stack_phys, header.stack_size],
[cast(ulong)header.bootinfo.fb.buffer, header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u], [cast(ulong)header.bootinfo.fb.buffer, header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u],
[header.bootinfo.pt_phys, header.bootinfo.pt_size],
]; ];
for (size_t ri = 0u; ri < reserved.length; ri++) for (size_t ri = 0u; ri < reserved.length; ri++)
{ {
@ -66,7 +65,8 @@ struct hippo
} }
for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++) for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++)
{ {
if (header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Conventional) if ((header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Bootloader) ||
(header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Conventional))
{ {
ulong phys = header.bootinfo.memory_map[bii].base; ulong phys = header.bootinfo.memory_map[bii].base;
ulong phys_end = phys + header.bootinfo.memory_map[bii].size; ulong phys_end = phys + header.bootinfo.memory_map[bii].size;