diff --git a/src/hello/hello.d b/src/hello/hello.d index d4d794c..1bd2bc8 100644 --- a/src/hello/hello.d +++ b/src/hello/hello.d @@ -5,7 +5,6 @@ module hello.hello; import uefi; import hello.console; -import hello.scratch; import hulk.bootinfo; import hulk.header; import hulk.pagetable; @@ -16,6 +15,9 @@ import ldc.llvmasm; __gshared EFI_SYSTEM_TABLE * st; extern extern(C) __gshared ubyte _hulk_bin_start; 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() { @@ -87,9 +89,9 @@ private bool in_qemu() private bool set_graphics_mode() { 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_HANDLE * handles = cast(EFI_HANDLE *)scratch.current(); + EFI_HANDLE * handles = cast(EFI_HANDLE *)&scratch_buffer[0]; EFI_STATUS status = st.BootServices.LocateHandle(ByProtocol, &gop_guid, null, &buffer_size, handles); 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 = [ 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.Bootloader, // EfiLoaderCode + BootInfo.MemoryRegion.Type.Bootloader, // EfiLoaderData + BootInfo.MemoryRegion.Type.Bootloader, // EfiBootServicesCode + BootInfo.MemoryRegion.Type.Bootloader, // EfiBootServicesData BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesCode BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesData 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 ]; *physical_address_limit = 0u; - UINTN memory_map_size = scratch.free(); + UINTN memory_map_size = scratch_buffer.sizeof; UINTN descriptor_size; UINT32 descriptor_version; - ubyte * scratch_base = scratch.current(); + ubyte * scratch_base = cast(ubyte *)&scratch_buffer[0]; UINTN status = st.BootServices.GetMemoryMap( &memory_map_size, 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. */ 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); return pt; } @@ -252,7 +279,7 @@ private PageTable * new_page_table() * @param dest_page Destination page 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; 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) { next_pt = new_page_table(); + if (next_pt == null) + { + return false; + } addr = cast(ulong)next_pt; } else @@ -280,6 +311,7 @@ private void map4k(ulong source_page, ulong dest_page, PageTable * pt_base) 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 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; while (source < end) { - map4k(source, dest, pt_base); + if (!map4k(source, dest, pt_base)) + { + return false; + } source += 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 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; 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) { next_pt = new_page_table(); + if (next_pt == null) + { + return false; + } *ppte = PageTableEntry(next_pt, PT_WRITABLE | PT_PRESENT); } else @@ -334,6 +374,7 @@ private void map2m(ulong source_page, ulong dest_page, PageTable * pt_base) 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. */ -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. */ 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. */ 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. */ 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. */ -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(); + if (pt_base == null) + { + return false; + } /* Map physical RAM. */ 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. */ 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; 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. */ ulong framebuffer_size = bootinfo().fb.height * bootinfo().fb.stride * 4u; ulong fb_phys = cast(ulong)bootinfo().fb.buffer; 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(pt_base, bss_phys, stack_phys); + if (!map_hulk(pt_base, bss_phys, stack_phys)) + { + return false; + } /* Switch to the new page table. */ 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; } - bootinfo().pt_phys = cast(ulong)scratch.current(); - if (!set_graphics_mode()) { console.wait_key(); @@ -477,12 +543,14 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st) 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().bss_phys = bss_phys; bootinfo().stack_phys = stack_phys; - bootinfo().pt_size = cast(ulong)scratch.current() - bootinfo().pt_phys; jump_to_hulk(); diff --git a/src/hello/scratch.d b/src/hello/scratch.d deleted file mode 100644 index dcbd2ab..0000000 --- a/src/hello/scratch.d +++ /dev/null @@ -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; - } -} diff --git a/src/hulk/bootinfo.d b/src/hulk/bootinfo.d index 3c4cfb5..f2cd712 100644 --- a/src/hulk/bootinfo.d +++ b/src/hulk/bootinfo.d @@ -33,6 +33,7 @@ struct BootInfo enum Type { Reserved, + Bootloader, Conventional, Unusable, ACPIReclaim, @@ -68,12 +69,6 @@ struct BootInfo /* Physical address of stack while jumping to HULK. */ 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. */ ulong acpi_xsdt_phys; } diff --git a/src/hulk/hippo.d b/src/hulk/hippo.d index 0ac19dc..d730e40 100644 --- a/src/hulk/hippo.d +++ b/src/hulk/hippo.d @@ -53,12 +53,11 @@ struct hippo public static void initialize(HulkHeader * header) { 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.bss_phys, LinkerAddresses.hulk_bss_size], [header.bootinfo.stack_phys, header.stack_size], [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++) { @@ -66,7 +65,8 @@ struct hippo } 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_end = phys + header.bootinfo.memory_map[bii].size;