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)
.section ".rodata"
.balign 4096
.global hulk_bin_start
hulk_bin_start:
.global _hulk_bin_start
_hulk_bin_start:
.incbin "#{@sources.first}"
.balign 4096
.global hulk_bin_end
hulk_bin_end:
.global _hulk_bin_end
_hulk_bin_end:
EOF
unless @cache.up_to_date?(@target, nil, @sources, @env)
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;
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_end;
extern extern(C) __gshared ubyte _hulk_bin_start;
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.
@ -94,11 +123,26 @@ private bool set_graphics_mode()
/**
* 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 descriptor_size;
UINT32 descriptor_version;
@ -106,29 +150,28 @@ private ulong get_memory_map()
UINTN status = st.BootServices.GetMemoryMap(
&memory_map_size,
cast(EFI_MEMORY_DESCRIPTOR *)scratch_base,
&memory_map_key,
memory_map_key,
&descriptor_size,
&descriptor_version);
if (status != EFI_SUCCESS)
{
console.writeln("GetMemoryMap: Error %x", status);
return 0u;
for (;;) {}
}
ulong max_physical_address;
size_t n_entries = memory_map_size / descriptor_size;
size_t count;
bool found_bss;
bool found_stack;
for (count = 0u; count < n_entries; count++)
{
if (count > bootinfo.memory_map.length)
{
console.writeln("Memory map too large");
for (;;)
{
}
for (;;) {}
}
EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size];
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 == EfiLoaderData) ||
(descriptor.Type == EfiBootServicesCode) ||
@ -137,14 +180,39 @@ private ulong get_memory_map()
(descriptor.Type == EfiRuntimeServicesData) ||
(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].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;
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.
*
@ -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.
*
* @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 hulk_bin_phys_start = cast(ulong)&hulk_bin_start;
bootinfo.hulk_phys = hulk_bin_phys_start;
ulong hulk_bin_phys_end = cast(ulong)&hulk_bin_end;
ulong phys_iter = hulk_bin_phys_start;
while (phys_iter < hulk_bin_phys_end)
{
map4k(virt, phys_iter, 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;
}
map4kregion(virt, hulk_bin_phys(), hulk_bin_size(), pt_base);
/* Map HULK bss region. */
virt += hulk_bin_size();
map4kregion(virt, bss_phys, hulk_bss_size(), pt_base);
/* Map HULK stack. */
virt += hulk_bss_size();
map4kregion(virt, stack_phys, hulk_stack_size(), pt_base);
}
/**
@ -295,7 +340,7 @@ private void map_hulk(PageTableEntry * pt_base)
*
* @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();
/* Map physical RAM. */
@ -323,7 +368,7 @@ private void build_page_tables(ulong max_physical_address)
map4k(addr, addr, pt_base);
}
/* 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. */
write_cr3(cast(ulong)pt_base);
}
@ -333,9 +378,8 @@ private void build_page_tables(ulong max_physical_address)
*/
private void jump_to_hulk()
{
HulkHeader * hulk_header = cast(HulkHeader *)&hulk_bin_start;
void function(BootInfo *) hulk_start = cast(void function(BootInfo *))hulk_header.entry;
hulk_start(&bootinfo);
void function(BootInfo *) hulk_entry_fn = cast(void function(BootInfo *))hulk_header().entry;
hulk_entry_fn(&bootinfo);
}
/**
@ -359,10 +403,13 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
return EFI_SUCCESS;
}
ulong bss_phys;
ulong stack_phys;
ulong max_physical_address;
UINTN memory_map_key;
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);
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;
}
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();

View File

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

View File

@ -20,4 +20,7 @@ struct Header
/** Entry point. */
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 = {
&_hulk_total_size,
&hulk_start,
16u * 1024u,
};
/**