diff --git a/Rsconscript b/Rsconscript index 7cd03db..5b95338 100644 --- a/Rsconscript +++ b/Rsconscript @@ -23,12 +23,12 @@ class HulkBinObj < Builder File.write(@target, <#{@target}", nil) diff --git a/src/hello/hello.d b/src/hello/hello.d index b72b937..d452125 100644 --- a/src/hello/hello.d +++ b/src/hello/hello.d @@ -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(); diff --git a/src/hulk/bootinfo.d b/src/hulk/bootinfo.d index 80950b8..8f610d4 100644 --- a/src/hulk/bootinfo.d +++ b/src/hulk/bootinfo.d @@ -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. */ diff --git a/src/hulk/header.d b/src/hulk/header.d index c8ad5a8..1bbef17 100644 --- a/src/hulk/header.d +++ b/src/hulk/header.d @@ -20,4 +20,7 @@ struct Header /** Entry point. */ void * entry; + + /** Stack size. */ + ulong stack_size; } diff --git a/src/hulk/hulk.d b/src/hulk/hulk.d index 9bb2a39..13058bd 100644 --- a/src/hulk/hulk.d +++ b/src/hulk/hulk.d @@ -18,6 +18,7 @@ extern extern(C) __gshared ubyte _hulk_total_size; private __gshared Header hulk_header = { &_hulk_total_size, &hulk_start, + 16u * 1024u, }; /**