diff --git a/src/hello/hello.d b/src/hello/hello.d index 4c2f47e..a8a9979 100644 --- a/src/hello/hello.d +++ b/src/hello/hello.d @@ -90,7 +90,7 @@ private bool set_graphics_mode() return true; } -private bool get_memory_map() +private ulong get_memory_map() { UINTN memory_map_size = scratch_free(); UINTN descriptor_size; @@ -105,26 +105,39 @@ private bool get_memory_map() if (status != EFI_SUCCESS) { writeln("GetMemoryMap: Error %x", status); - return false; + return 0u; } + ulong max_physical_address; size_t n_entries = memory_map_size / descriptor_size; - size_t di; - for (size_t i = 0u; i < n_entries; i++) + size_t count; + for (count = 0u; count < n_entries; count++) { - EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[i * descriptor_size]; - if ((descriptor.Type == EfiLoaderCode) || - (descriptor.Type == EfiLoaderData) || - (descriptor.Type == EfiBootServicesCode) || - (descriptor.Type == EfiBootServicesCode) || - (descriptor.Type == EfiConventionalMemory)) + if (count > bootinfo.memory_map.length) { - bootinfo.memory_map[di].base = descriptor.PhysicalStart; - bootinfo.memory_map[di].size = descriptor.NumberOfPages * 4096u; - di++; + writeln("Memory map too large"); + 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) && + ((descriptor.Type == EfiLoaderCode) || + (descriptor.Type == EfiLoaderData) || + (descriptor.Type == EfiBootServicesCode) || + (descriptor.Type == EfiBootServicesData) || + (descriptor.Type == EfiRuntimeServicesCode) || + (descriptor.Type == EfiRuntimeServicesData) || + (descriptor.Type == EfiConventionalMemory))) + { + max_physical_address = end_address; + } + 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 = di; - return true; + bootinfo.memory_map_count = count; + return max_physical_address; } private PageTableEntry * new_page_table() @@ -134,7 +147,7 @@ private PageTableEntry * new_page_table() return pt; } -private void map(ulong source_page, ulong dest_page, PageTableEntry * pt_base) +private void map4k(ulong source_page, ulong dest_page, PageTableEntry * pt_base) { PageTableEntry * pt = pt_base; PageTableEntry * next_pt; @@ -164,32 +177,77 @@ private void map(ulong source_page, ulong dest_page, PageTableEntry * pt_base) } } +private void map2m(ulong source_page, ulong dest_page, PageTableEntry * pt_base) +{ + PageTableEntry * pt = pt_base; + PageTableEntry * next_pt; + for (size_t level = 0; level < 3u; level++) + { + size_t pt_index = PageTableEntry.page_table_index(source_page, level); + if (pt[pt_index].present()) + { + pt = pt[pt_index].next(); + } + else + { + if (level < 2u) + { + next_pt = new_page_table(); + pt[pt_index] = PageTableEntry(cast(ulong)next_pt, + 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u); + } + else + { + pt[pt_index] = PageTableEntry(dest_page, + 0u, 0u, 1u, 0u, 0u, 0u, 1u, 1u); + } + pt = next_pt; + } + } +} + private void map_hulk(PageTableEntry * pt_base) { ulong virt = HULK_VIRTUAL_START; ulong phys = cast(ulong)&hulk_start; while (phys < cast(ulong)&hulk_end) { - map(virt, phys, pt_base); + map4k(virt, phys, pt_base); virt += 4096u; phys += 4096u; } } -private void build_page_tables() +private void build_page_tables(ulong max_physical_address) { PageTableEntry * pt_base = new_page_table(); + /* Map physical RAM. */ + for (size_t addr = 0u; addr < max_physical_address; addr += (2u * 1024u * 1024u)) + { + map2m(addr, addr, pt_base); + } + /* Map any memory regions that are outside physical RAM. */ for (size_t i = 0u; i < bootinfo.memory_map_count; i++) { - size_t n_pages = bootinfo.memory_map[i].size / 4096u; - for (size_t p = 0u; p < n_pages; p++) + if (bootinfo.memory_map[i].base > max_physical_address) { - ulong page_addr = bootinfo.memory_map[i].base + 4096u * p; - /* Identity map all pages. */ - map(page_addr, page_addr, pt_base); + for (size_t offset = 0u; offset < bootinfo.memory_map[i].size; offset += 4096u) + { + ulong addr = bootinfo.memory_map[i].base + offset; + map4k(addr, addr, pt_base); + } } } + /* Map graphics framebuffer. */ + ulong framebuffer_size = bootinfo.fb.height * bootinfo.fb.stride; + for (size_t offset = 0u; offset < framebuffer_size; offset++) + { + ulong addr = cast(ulong)bootinfo.fb.buffer + offset; + map4k(addr, addr, pt_base); + } + /* Map HULK to its requested starting virtual address. */ map_hulk(pt_base); + /* Switch to the new page table. */ write_cr3(cast(ulong)pt_base); } @@ -214,9 +272,10 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st) return EFI_SUCCESS; } + ulong max_physical_address; for (;;) { - get_memory_map(); + max_physical_address = get_memory_map(); EFI_STATUS status = st.BootServices.ExitBootServices(image_handle, memory_map_key); if (status == EFI_INVALID_PARAMETER) @@ -232,7 +291,7 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st) return EFI_SUCCESS; } - build_page_tables(); + build_page_tables(max_physical_address); jump_to_hulk(); diff --git a/src/hulk/hulk/bootinfo.d b/src/hulk/hulk/bootinfo.d index a4842d9..11999d9 100644 --- a/src/hulk/hulk/bootinfo.d +++ b/src/hulk/hulk/bootinfo.d @@ -4,6 +4,7 @@ struct BootInfo { ulong base; size_t size; + ubyte type; } struct Framebuffer { @@ -15,7 +16,7 @@ struct BootInfo } Framebuffer fb; - MemoryRegion[500] memory_map; + MemoryRegion[800] memory_map; size_t memory_map_count; }