Allocate HULK stack region from HELLO, translate memory region types
This commit is contained in:
parent
f236a64b21
commit
f29bd9d00c
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -20,4 +20,7 @@ struct Header
|
||||
|
||||
/** Entry point. */
|
||||
void * entry;
|
||||
|
||||
/** Stack size. */
|
||||
ulong stack_size;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ extern extern(C) __gshared ubyte _hulk_total_size;
|
||||
private __gshared Header hulk_header = {
|
||||
&_hulk_total_size,
|
||||
&hulk_start,
|
||||
16u * 1024u,
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user