diff --git a/src/common/hos/page_table.d b/src/common/hos/page_table.d new file mode 100644 index 0000000..59a0767 --- /dev/null +++ b/src/common/hos/page_table.d @@ -0,0 +1,33 @@ +struct PageTableEntry +{ + ulong entry; + + this(ulong address, ulong no_execute, ulong global, + ulong huge, ulong disable_cache, ulong write_through, ulong user, + ulong writable, ulong present) + { + entry = (present | + (writable << 1) | + (user << 2) | + (write_through << 3) | + (disable_cache << 4) | + (huge << 7) | + (global << 8) | + (no_execute << 63)) | address; + } + + bool present() + { + return (entry & 0x1u) != 0u; + } + + PageTableEntry * next() + { + return cast(PageTableEntry *)(entry & 0x7FFF_FFFF_FFFF_F000u); + } + + static ulong page_table_index(ulong address, size_t level) + { + return ((address >> (39u - 9u * level)) & 0x1FFu); + } +} diff --git a/src/hello/hello.d b/src/hello/hello.d index 5d8f617..e8d68f3 100644 --- a/src/hello/hello.d +++ b/src/hello/hello.d @@ -2,6 +2,8 @@ import uefi; import output; import scratch; import hulk.bootinfo; +import hos.page_table; +import hos.cpu; __gshared EFI_SYSTEM_TABLE * st; __gshared BootInfo bootinfo; @@ -111,7 +113,7 @@ private bool get_memory_map() (descriptor.Type == EfiBootServicesCode) || (descriptor.Type == EfiBootServicesData)) { - bootinfo.memory_map[di].base = cast(void *)descriptor.PhysicalStart; + bootinfo.memory_map[di].base = descriptor.PhysicalStart; bootinfo.memory_map[di].size = descriptor.NumberOfPages * 4096u; di++; } @@ -120,6 +122,57 @@ private bool get_memory_map() return true; } +private PageTableEntry * new_page_table() +{ + return cast(PageTableEntry *)scratch_alloc(1u); +} + +private void map(ulong source_page, ulong dest_page, PageTableEntry * pt_base) +{ + PageTableEntry * pt = pt_base; + PageTableEntry * next_pt; + for (size_t level = 0; level < 4u; level++) + { + size_t pt_index = PageTableEntry.page_table_index(source_page, level); + if (pt[pt_index].present()) + { + pt = pt[pt_index].next(); + } + else + { + ulong addr; + if (level < 3u) + { + next_pt = new_page_table(); + addr = cast(ulong)next_pt; + } + else + { + addr = dest_page; + } + pt[pt_index] = PageTableEntry(addr, + 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u); + pt = next_pt; + } + } +} + +private void build_page_tables() +{ + PageTableEntry * pt_base = new_page_table(); + 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++) + { + ulong page_addr = bootinfo.memory_map[i].base + 4096u * p; + /* Identity map all pages. */ + map(page_addr, page_addr, pt_base); + } + } + write_cr3(cast(ulong)pt_base); +} + extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st) { .st = st; @@ -153,5 +206,7 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st) return EFI_SUCCESS; } + build_page_tables(); + return EFI_SUCCESS; } diff --git a/src/hulk/hulk/bootinfo.d b/src/hulk/hulk/bootinfo.d index 8da62cf..752b882 100644 --- a/src/hulk/hulk/bootinfo.d +++ b/src/hulk/hulk/bootinfo.d @@ -2,7 +2,7 @@ struct BootInfo { struct MemoryRegion { - void * base; + ulong base; size_t size; } struct Framebuffer