From 693e533cf72eaf6cd41769fc76561b412328adae Mon Sep 17 00:00:00 2001 From: Amelia Coutard Date: Sun, 10 Dec 2023 11:34:07 +0100 Subject: [PATCH] Simplified the page mapping editing function, and genericised it --- kernel/src/boot.S | 3 ++- kernel/src/elf64.cpp | 8 +++++--- kernel/src/interrupts.cpp | 10 ++++++++-- kernel/src/kernel.cpp | 15 +++++++------- kernel/src/paging.cpp | 39 ------------------------------------- kernel/src/paging.hpp | 41 ++++++++++++++++++++++++--------------- 6 files changed, 47 insertions(+), 69 deletions(-) diff --git a/kernel/src/boot.S b/kernel/src/boot.S index f9adf20..279767a 100644 --- a/kernel/src/boot.S +++ b/kernel/src/boot.S @@ -201,10 +201,11 @@ _start: or $1 << 7, %eax # PGE mov %eax, %cr4 - # Set long mode bit: + # Set long mode bit (and NXE): mov $0xC0000080, %ecx rdmsr or $1 << 8, %eax + or $1 << 11, %eax wrmsr # Enable paging: mov %cr0, %eax diff --git a/kernel/src/elf64.cpp b/kernel/src/elf64.cpp index 88fbf29..d5acce1 100644 --- a/kernel/src/elf64.cpp +++ b/kernel/src/elf64.cpp @@ -73,9 +73,11 @@ void os::elf::load_elf(os::process& result, std::byte* start, std::size_t length // Allocate, map and initialise memory for segment (memory above program_header.p_filesz is already 0-initialised by the page allocator): std::size_t nb_pages = (std::uint64_t(program_header.p_vaddr) % 0x1000 + program_header.p_memsz + 0x1000 - 1) / 0x1000; for (std::size_t i = 0; i < nb_pages; i++) { - std::byte* const page = - os::paging::setup_page(*result.PML4T, program_header.p_vaddr + i * 0x1000, (program_header.flags & 2) >> 1, 1); - memcpy(page, start + program_header.p_offset, clamp(0ul, program_header.p_filesz - i * 0x1000, 0x1000ul)); + auto const alloc = os::paging::page_allocator.allocate(1); + os::assert(alloc.ptr != nullptr, "Failed to allocate enough memory for loading of elf binary."); + os::paging::map_page(*result.PML4T, (os::paging::page<0>*)(program_header.p_vaddr + i * 0x1000), alloc.ptr, + {.R_W = (program_header.flags & 2) >> 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 1 - (program_header.flags & 1)}); + memcpy((void*)alloc.ptr, start + program_header.p_offset, clamp(0ul, program_header.p_filesz - i * 0x1000, 0x1000ul)); } } } diff --git a/kernel/src/interrupts.cpp b/kernel/src/interrupts.cpp index 477431f..0af446a 100644 --- a/kernel/src/interrupts.cpp +++ b/kernel/src/interrupts.cpp @@ -111,13 +111,19 @@ extern "C" void int_page_fault(std::uint32_t err_code, std::uint64_t vaddr) { (0xFFFF'C000'0000'0000 <= vaddr && vaddr < 0xFFFF'C000'1000'0000) // process/port info ) { // Kernel memory os::print("Allocating (Ring 0): {}\n", (void*)vaddr); - os::paging::setup_page(os::paging::global_PML4T, (void*)vaddr, true, false); + auto const alloc = os::paging::page_allocator.allocate(1); + os::assert(alloc.ptr != nullptr, "Out of memory."); + os::paging::map_page(os::paging::global_PML4T, (os::paging::page<0>*)vaddr, alloc.ptr, + {.R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .PAT = 0, .G = 1, .base_address = 0, .NX = 1}); return; } else if ( (0x0000'7FFF'FFFF'0000 <= vaddr && vaddr < 0x0000'8000'0000'0000) // stack ) { // Userspace memory os::print("Allocating (Ring 3): {}\n", (void*)vaddr); - os::paging::setup_page(*os::get_process(os::current_pid).PML4T, (void*)vaddr, true, true); + auto const alloc = os::paging::page_allocator.allocate(1); + os::assert(alloc.ptr != nullptr, "Out of memory."); + os::paging::map_page(*os::get_process(os::current_pid).PML4T, (os::paging::page<0>*)vaddr, alloc.ptr, + {.R_W = 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 1}); return; } os::print("Interrupt: Page Fault.\n"); diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 5093a0d..9babbd5 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -28,13 +28,17 @@ os::paging::page<0> bootstrap_pages_for_memory[32]; // 32 pages = 128 KiB extern "C" void kmain(unsigned long magic, os::phys_ptr info) { os::assert(magic == 0x36D76289, "Incorrect magic number: wasn't booted with multiboot2."); + + os::paging::page_allocator.deallocate({ + .ptr = os::phys_ptr>(reinterpret_cast(bootstrap_pages_for_memory) - 0xFFFF'FFFF'8000'0000), + .size = sizeof(bootstrap_pages_for_memory) / sizeof(bootstrap_pages_for_memory[0]) + }); + os::assert(os::cpu_has_msr(), "MSRs aren't supported."); // TODO: Initialise new PML4T os::paging::global_PML4T = old_PML4T; // /TODO - os::print("a\n"); os::paging::load_pml4t(os::phys_ptr{std::uintptr_t(&os::paging::global_PML4T) - 0xFFFF'FFFF'8000'0000}); - os::print("b\n"); if (!os::init_serial_port()) { while (true) { @@ -42,11 +46,6 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr>(reinterpret_cast(bootstrap_pages_for_memory) - 0xFFFF'FFFF'8000'0000), - .size = sizeof(bootstrap_pages_for_memory) / sizeof(bootstrap_pages_for_memory[0]) - }); - { // Enable interrupts really early so I don't have to manually manage memory... Will make better later, when I make utils.hpp/incrementing_int64_map better. os::isr_info isr_info[32]; for (size_t i = 0; i < sizeof(isr_info) / sizeof(isr_info[0]); i++) { @@ -91,7 +90,7 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr> (12 + 9 * 3)) & 0x1FF; os::paging::global_PML4T.contents[index] = {.non_page = {.P = 1, .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; const auto PDPT_alloc = os::paging::page_allocator.allocate(1); os::memset((void*)PDPT_alloc.ptr, 0, 0x1000); diff --git a/kernel/src/paging.cpp b/kernel/src/paging.cpp index 2d44735..845e69a 100644 --- a/kernel/src/paging.cpp +++ b/kernel/src/paging.cpp @@ -16,45 +16,6 @@ os::paging::PML4T os::paging::global_PML4T; -std::byte* os::paging::setup_page(os::paging::PML4T& PML4T, const void* vaddr, bool R_W, bool U_S) { - const auto indices = os::paging::calc_page_table_indices(vaddr); - if (PML4T.contents[indices.pml4e].non_page.P == 0) { - PML4T.contents[indices.pml4e] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; - const auto PDPT_alloc = os::paging::page_allocator.allocate(1); - memset((void*)PDPT_alloc.ptr, 0, 0x1000); - set_base_address(PML4T.contents[indices.pml4e], os::phys_ptr(PDPT_alloc.ptr.get_phys_addr())); - } - os::paging::PDPT& PDPT = *get_base_address(PML4T.contents[indices.pml4e]); - if (PDPT.contents[indices.pdpe].non_page.P == 0) { - PDPT.contents[indices.pdpe] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; - const auto PDT_alloc = os::paging::page_allocator.allocate(1); - memset((void*)PDT_alloc.ptr, 0, 0x1000); - set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr(PDT_alloc.ptr.get_phys_addr())); - } else { - assert(PDPT.contents[indices.pdpe].non_page.zero == 0, - "Cannot map memory address 0x{} because it is inside a 1GiB page", std::uintptr_t(vaddr)); - } - os::paging::PDT& PDT = *get_base_address(PDPT.contents[indices.pdpe]); - if (PDT.contents[indices.pde].non_page.P == 0) { - PDT.contents[indices.pde] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; - const auto PT_alloc = os::paging::page_allocator.allocate(1); - memset((void*)PT_alloc.ptr, 0, 0x1000); - set_base_address(PDT.contents[indices.pde], os::phys_ptr(PT_alloc.ptr.get_phys_addr())); - } else { - assert(PDT.contents[indices.pde].non_page.zero == 0, - "Cannot map memory address 0x{} because it is inside a 2MiB page", std::uintptr_t(vaddr)); - } - os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]); - os::assert(PT.contents[indices.pe].page.P == 0, "Memory at address 0x{} has already been mapped.", std::uintptr_t(vaddr)); - PT.contents[indices.pe] = - {.page = {.P = 1, .R_W = R_W, .U_S = U_S, .PWT = 0, .PCD = 0, .PAT = 0, .G = (indices.pml4e < 128) ? 0ul : 1ul, .base_address = 0, .NX = 0}}; - const auto page_alloc = os::paging::page_allocator.allocate(1); - memset((void*)page_alloc.ptr, 0, 0x1000); - set_page_base_address(PT.contents[indices.pe], os::phys_ptr>(page_alloc.ptr.get_phys_addr())); - invlpg(vaddr); - return (std::byte*)&*page_alloc.ptr; -} - namespace { void on_all_pages(const os::paging::PT& PT, void f(os::paging::page<0>*, os::phys_ptr>, std::size_t), std::size_t PT_virt_address) { for (std::size_t i = 0; i < 512; i++) { diff --git a/kernel/src/paging.hpp b/kernel/src/paging.hpp index eb1696f..09ba64e 100644 --- a/kernel/src/paging.hpp +++ b/kernel/src/paging.hpp @@ -195,22 +195,8 @@ template void set_page_base_address(paging_entry& entry, p entry.page.base_address = ptr.get_phys_addr() / sizeof(page); } -struct page_table_indices { - std::uint16_t pml4e; - std::uint16_t pdpe; - std::uint16_t pde; - std::uint16_t pe; -}; -constexpr page_table_indices calc_page_table_indices(const void* ptr) { - return { - .pml4e = std::uint16_t((std::uint64_t(ptr) >> 39) & 0x1FF), - .pdpe = std::uint16_t((std::uint64_t(ptr) >> 30) & 0x1FF), - .pde = std::uint16_t((std::uint64_t(ptr) >> 21) & 0x1FF), - .pe = std::uint16_t((std::uint64_t(ptr) >> 12) & 0x1FF), - }; -} - -std::byte* setup_page(PML4T& PML4T, const void* vaddr, bool R_W, bool U_S); +template +void map_page(paging_table& paging_table, page const* vaddr, phys_ptr> phys_addr, decltype(paging_entry::page) page_info); // For all present page mappings, calls f(virtual address, physical address, page size in bytes (4KiB, 2MiB or 1GiB)). void on_all_pages(const PML4T& PML4T, void f(page<0>*, phys_ptr>, std::size_t)); @@ -245,4 +231,27 @@ private: bool merge(phys_ptr it); }; +template +void map_page(paging_table& paging_table, page const* vaddr, phys_ptr> phys_addr, decltype(paging_entry::page) page_info) { + std::size_t const index = (std::uint64_t(vaddr) >> (12 + 9 * paging_depth)) & 0x1FF; + if constexpr (depth == paging_depth) { + os::assert(paging_table.contents[index].page.P == 0, "Virtual address 0x{} is already mapped.", vaddr); + paging_table.contents[index].page = page_info; + paging_table.contents[index].page.P = 1; + set_page_base_address(paging_table.contents[index], phys_addr); + invlpg(vaddr); + } else { + if (paging_table.contents[index].non_page.P == 1) { + assert(!is_page(paging_table.contents[index]), "Virtual address 0x{} is already in a mapped page.", vaddr); + } else { + auto const alloc = page_allocator.allocate(1); + assert(alloc.ptr != nullptr, "Not enough RAM to create the paging structures."); + memset((void*)alloc.ptr, 0, 0x1000); + paging_table.contents[index].non_page = {.P = 1, .R_W = 1, .U_S = page_info.U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}; + set_base_address(paging_table.contents[index], os::phys_ptr>{alloc.ptr.get_phys_addr()}); + } + map_page(*get_base_address(paging_table.contents[index]), vaddr, phys_addr, page_info); + } +} + } } // namespace os::paging -- 2.47.0