Allocate HULK stack region from HELLO, translate memory region types

This commit is contained in:
Josh Holtrop 2022-03-26 00:29:19 -04:00
parent f236a64b21
commit f29bd9d00c
5 changed files with 148 additions and 81 deletions

View File

@ -23,12 +23,12 @@ class HulkBinObj < Builder
File.write(@target, <<EOF) File.write(@target, <<EOF)
.section ".rodata" .section ".rodata"
.balign 4096 .balign 4096
.global hulk_bin_start .global _hulk_bin_start
hulk_bin_start: _hulk_bin_start:
.incbin "#{@sources.first}" .incbin "#{@sources.first}"
.balign 4096 .balign 4096
.global hulk_bin_end .global _hulk_bin_end
hulk_bin_end: _hulk_bin_end:
EOF EOF
unless @cache.up_to_date?(@target, nil, @sources, @env) unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Creating HULK binary object <target>#{@target}<reset>", nil) print_run_message("Creating HULK binary object <target>#{@target}<reset>", nil)

View File

@ -14,9 +14,38 @@ import hos.memory;
__gshared EFI_SYSTEM_TABLE * st; __gshared EFI_SYSTEM_TABLE * st;
private __gshared BootInfo bootinfo; private __gshared BootInfo bootinfo;
private __gshared UINTN memory_map_key; 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 HulkHeader * hulk_header()
{
return cast(HulkHeader *)&_hulk_bin_start;
}
private ulong hulk_bin_phys()
{
return cast(ulong)&_hulk_bin_start;
}
private ulong hulk_bin_size()
{
return cast(ulong)&_hulk_bin_end - cast(ulong)&_hulk_bin_start;
}
private ulong hulk_total_size()
{
return cast(ulong)hulk_header().total_size;
}
private ulong hulk_bss_size()
{
return hulk_total_size() - hulk_bin_size();
}
private ulong hulk_stack_size()
{
return hulk_header().stack_size;
}
/** /**
* Detect if we're running in QEMU. * Detect if we're running in QEMU.
@ -94,11 +123,26 @@ private bool set_graphics_mode()
/** /**
* Walk the EFI memory map and translate it to the HULK bootinfo format. * Walk the EFI memory map and translate it to the HULK bootinfo format.
*
* @return Maximum physical address to identity map.
*/ */
private ulong get_memory_map() private void get_memory_map(ulong * bss_phys, ulong * stack_phys, ulong * max_physical_address, UINTN * memory_map_key)
{ {
immutable static ubyte[] efi_to_hulk_memory_map_type = [
BootInfo.MemoryRegion.Type.Reserved, // EfiReservedMemoryType
BootInfo.MemoryRegion.Type.Conventional, // EfiLoaderCode
BootInfo.MemoryRegion.Type.Conventional, // EfiLoaderData
BootInfo.MemoryRegion.Type.Conventional, // EfiBootServicesCode
BootInfo.MemoryRegion.Type.Conventional, // EfiBootServicesData
BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesCode
BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesData
BootInfo.MemoryRegion.Type.Conventional, // EfiConventionalMemory
BootInfo.MemoryRegion.Type.Unusable, // EfiUnusableMemory
BootInfo.MemoryRegion.Type.ACPIReclaim, // EfiACPIReclaimMemory
BootInfo.MemoryRegion.Type.ACPINVS, // EfiACPIMemoryNVS
BootInfo.MemoryRegion.Type.MemoryMappedIO, // EfiMemoryMappedIO
BootInfo.MemoryRegion.Type.MemoryMappedIOPortSpace, // EfiMemoryMappedIOPortSpace
BootInfo.MemoryRegion.Type.PalCode, // EfiPalCode
];
*max_physical_address = 0u;
UINTN memory_map_size = scratch.free(); UINTN memory_map_size = scratch.free();
UINTN descriptor_size; UINTN descriptor_size;
UINT32 descriptor_version; UINT32 descriptor_version;
@ -106,29 +150,28 @@ private ulong get_memory_map()
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,
&memory_map_key, memory_map_key,
&descriptor_size, &descriptor_size,
&descriptor_version); &descriptor_version);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
{ {
console.writeln("GetMemoryMap: Error %x", status); console.writeln("GetMemoryMap: Error %x", status);
return 0u; for (;;) {}
} }
ulong max_physical_address;
size_t n_entries = memory_map_size / descriptor_size; size_t n_entries = memory_map_size / descriptor_size;
size_t count; size_t count;
bool found_bss;
bool found_stack;
for (count = 0u; count < n_entries; count++) for (count = 0u; count < n_entries; count++)
{ {
if (count > bootinfo.memory_map.length) if (count > bootinfo.memory_map.length)
{ {
console.writeln("Memory map too large"); console.writeln("Memory map too large");
for (;;) for (;;) {}
{
}
} }
EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size]; EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size];
ulong end_address = descriptor.PhysicalStart + descriptor.NumberOfPages * 4096u; ulong end_address = descriptor.PhysicalStart + descriptor.NumberOfPages * 4096u;
if ((end_address > max_physical_address) && if ((end_address > *max_physical_address) &&
((descriptor.Type == EfiLoaderCode) || ((descriptor.Type == EfiLoaderCode) ||
(descriptor.Type == EfiLoaderData) || (descriptor.Type == EfiLoaderData) ||
(descriptor.Type == EfiBootServicesCode) || (descriptor.Type == EfiBootServicesCode) ||
@ -137,14 +180,39 @@ private ulong get_memory_map()
(descriptor.Type == EfiRuntimeServicesData) || (descriptor.Type == EfiRuntimeServicesData) ||
(descriptor.Type == EfiConventionalMemory))) (descriptor.Type == EfiConventionalMemory)))
{ {
max_physical_address = end_address; *max_physical_address = end_address;
}
if (descriptor.Type >= efi_to_hulk_memory_map_type.length)
{
continue;
} }
bootinfo.memory_map[count].base = descriptor.PhysicalStart; bootinfo.memory_map[count].base = descriptor.PhysicalStart;
bootinfo.memory_map[count].size = descriptor.NumberOfPages * 4096u; bootinfo.memory_map[count].size = descriptor.NumberOfPages * 4096u;
bootinfo.memory_map[count].type = cast(ubyte)descriptor.Type; bootinfo.memory_map[count].type = efi_to_hulk_memory_map_type[descriptor.Type];
if ((!found_bss) &&
(descriptor.Type == EfiConventionalMemory) &&
(bootinfo.memory_map[count].size >= hulk_bss_size()))
{
*bss_phys = bootinfo.memory_map[count].base;
bootinfo.memory_map[count].base += hulk_bss_size();
bootinfo.memory_map[count].size -= hulk_bss_size();
found_bss = true;
}
if ((!found_stack) &&
(descriptor.Type == EfiConventionalMemory) &&
(bootinfo.memory_map[count].size >= hulk_stack_size()))
{
*stack_phys = bootinfo.memory_map[count].base;
bootinfo.memory_map[count].base += hulk_stack_size();
bootinfo.memory_map[count].size -= hulk_stack_size();
found_stack = true;
}
} }
bootinfo.memory_map_count = count; bootinfo.memory_map_count = count;
return max_physical_address; if ((!found_bss) && (!found_stack))
{
for (;;) {}
}
} }
/** /**
@ -194,6 +262,25 @@ private void map4k(ulong source_page, ulong dest_page, PageTableEntry * pt_base)
} }
} }
/**
* Map a virtual region to a physical region using 4KB pages.
*
* @param source Source address.
* @param dest Destination address.
* @param size Region size.
* @param pt_base Page table base address.
*/
private void map4kregion(ulong source, ulong dest, size_t size, PageTableEntry * pt_base)
{
ulong end = source + size;
while (source < end)
{
map4k(source, dest, pt_base);
source += 4096u;
dest += 4096u;
}
}
/** /**
* Map a virtual address to a physical address using 2MB pages. * Map a virtual address to a physical address using 2MB pages.
* *
@ -230,64 +317,22 @@ private void map2m(ulong source_page, ulong dest_page, PageTableEntry * pt_base)
} }
} }
/**
* Allocate a memory region for the HULK bss section.
*
* @param bss_size Size of the HULK bss section.
*
* @return Physical memory address.
*/
private ulong alloc_hulk_bss(size_t bss_size)
{
for (size_t i = 0u; i < bootinfo.memory_map_count; i++)
{
if ((bootinfo.memory_map[i].type == EfiConventionalMemory) &&
(bootinfo.memory_map[i].size >= bss_size))
{
memset64(cast(void *)bootinfo.memory_map[i].base, 0u, bss_size / 8u);
return bootinfo.memory_map[i].base;
}
}
/* We failed to find free memory. */
for (;;)
{
}
}
/** /**
* Map HULK virtual addresses to physical kernel location. * Map HULK virtual addresses to physical kernel location.
* *
* @param pt_base Page table base address. * @param pt_base Page table base address.
*/ */
private void map_hulk(PageTableEntry * pt_base) private void map_hulk(PageTableEntry * pt_base, ulong bss_phys, ulong stack_phys)
{ {
/* Map HULK bin region. */
ulong virt = HULK_VIRTUAL_START; ulong virt = HULK_VIRTUAL_START;
ulong hulk_bin_phys_start = cast(ulong)&hulk_bin_start; map4kregion(virt, hulk_bin_phys(), hulk_bin_size(), pt_base);
bootinfo.hulk_phys = hulk_bin_phys_start; /* Map HULK bss region. */
ulong hulk_bin_phys_end = cast(ulong)&hulk_bin_end; virt += hulk_bin_size();
ulong phys_iter = hulk_bin_phys_start; map4kregion(virt, bss_phys, hulk_bss_size(), pt_base);
while (phys_iter < hulk_bin_phys_end) /* Map HULK stack. */
{ virt += hulk_bss_size();
map4k(virt, phys_iter, pt_base); map4kregion(virt, stack_phys, hulk_stack_size(), pt_base);
virt += 4096u;
phys_iter += 4096u;
}
/* Now the binary has been mapped, but the bss section still needs to be
* allocated, zeroed and mapped. */
HulkHeader * hulk_header = cast(HulkHeader *)&hulk_bin_start;
size_t hulk_bin_phys_size = hulk_bin_phys_end - hulk_bin_phys_end;
size_t bss_size = cast(size_t)hulk_header.total_size - hulk_bin_phys_size;
ulong bss_phys = alloc_hulk_bss(bss_size);
bootinfo.bss_phys = bss_phys;
bootinfo.bss_size = bss_size;
ulong bss_phys_end = bss_phys + bss_size;
while (bss_phys < bss_phys_end)
{
map4k(virt, bss_phys, pt_base);
virt += 4096u;
bss_phys += 4096u;
}
} }
/** /**
@ -295,7 +340,7 @@ private void map_hulk(PageTableEntry * pt_base)
* *
* @param max_physical_address Maximum physical address to identity map. * @param max_physical_address Maximum physical address to identity map.
*/ */
private void build_page_tables(ulong max_physical_address) private void build_page_tables(ulong max_physical_address, ulong bss_phys, ulong stack_phys)
{ {
PageTableEntry * pt_base = new_page_table(); PageTableEntry * pt_base = new_page_table();
/* Map physical RAM. */ /* Map physical RAM. */
@ -323,7 +368,7 @@ private void build_page_tables(ulong max_physical_address)
map4k(addr, addr, pt_base); map4k(addr, addr, pt_base);
} }
/* Map HULK to its requested starting virtual address. */ /* Map HULK to its requested starting virtual address. */
map_hulk(pt_base); map_hulk(pt_base, bss_phys, stack_phys);
/* Switch to the new page table. */ /* Switch to the new page table. */
write_cr3(cast(ulong)pt_base); write_cr3(cast(ulong)pt_base);
} }
@ -333,9 +378,8 @@ private void build_page_tables(ulong max_physical_address)
*/ */
private void jump_to_hulk() private void jump_to_hulk()
{ {
HulkHeader * hulk_header = cast(HulkHeader *)&hulk_bin_start; void function(BootInfo *) hulk_entry_fn = cast(void function(BootInfo *))hulk_header().entry;
void function(BootInfo *) hulk_start = cast(void function(BootInfo *))hulk_header.entry; hulk_entry_fn(&bootinfo);
hulk_start(&bootinfo);
} }
/** /**
@ -359,10 +403,13 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
ulong bss_phys;
ulong stack_phys;
ulong max_physical_address; ulong max_physical_address;
UINTN memory_map_key;
for (;;) for (;;)
{ {
max_physical_address = get_memory_map(); get_memory_map(&bss_phys, &stack_phys, &max_physical_address, &memory_map_key);
EFI_STATUS status = st.BootServices.ExitBootServices(image_handle, memory_map_key); EFI_STATUS status = st.BootServices.ExitBootServices(image_handle, memory_map_key);
if (status == EFI_INVALID_PARAMETER) if (status == EFI_INVALID_PARAMETER)
@ -378,7 +425,11 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
build_page_tables(max_physical_address); build_page_tables(max_physical_address, bss_phys, stack_phys);
bootinfo.hulk_phys = hulk_bin_phys();
bootinfo.bss_phys = bss_phys;
bootinfo.stack_phys = stack_phys;
jump_to_hulk(); jump_to_hulk();

View File

@ -30,6 +30,18 @@ struct BootInfo
*/ */
struct MemoryRegion struct MemoryRegion
{ {
enum Type
{
Reserved,
Conventional,
Unusable,
ACPIReclaim,
ACPINVS,
MemoryMappedIO,
MemoryMappedIOPortSpace,
PalCode,
}
/** Base address of the memory region. */ /** Base address of the memory region. */
ulong base; ulong base;
/** Size in bytes of the memory region. */ /** Size in bytes of the memory region. */
@ -42,7 +54,7 @@ struct BootInfo
Framebuffer fb; Framebuffer fb;
/* Memory map. */ /* Memory map. */
MemoryRegion[800] memory_map; MemoryRegion[1000] memory_map;
/* Number of memory map entries. */ /* Number of memory map entries. */
size_t memory_map_count; size_t memory_map_count;
@ -53,8 +65,8 @@ struct BootInfo
/* Physical address used for HULK bss section. */ /* Physical address used for HULK bss section. */
ulong bss_phys; ulong bss_phys;
/* Size of HULK bss region. */ /* Physical address of stack while jumping to HULK. */
ulong bss_size; ulong stack_phys;
} }
/** HULK base virtual address. */ /** HULK base virtual address. */

View File

@ -20,4 +20,7 @@ struct Header
/** Entry point. */ /** Entry point. */
void * entry; void * entry;
/** Stack size. */
ulong stack_size;
} }

View File

@ -18,6 +18,7 @@ extern extern(C) __gshared ubyte _hulk_total_size;
private __gshared Header hulk_header = { private __gshared Header hulk_header = {
&_hulk_total_size, &_hulk_total_size,
&hulk_start, &hulk_start,
16u * 1024u,
}; };
/** /**