From 6e9a5cdbaba4131c01505471827e3e64cfaae686 Mon Sep 17 00:00:00 2001 From: Amelia Coutard Date: Fri, 10 Mar 2023 18:06:39 +0100 Subject: [PATCH] Moved elf loading to elf64.?pp, added the start of the needed architecture for multiple processes and IPC --- doc.txt | 4 +- kernel/src/elf64.cpp | 63 +++++++++++++++++++++++++++++ kernel/src/elf64.hpp | 4 +- kernel/src/kernel.cpp | 93 ++++++++++++++++--------------------------- kernel/src/paging.cpp | 6 ++- kernel/src/paging.hpp | 4 +- kernel/src/ring3.cpp | 2 + kernel/src/ring3.hpp | 30 ++++++++++++++ 8 files changed, 144 insertions(+), 62 deletions(-) diff --git a/doc.txt b/doc.txt index b450d6b..61b3dcc 100644 --- a/doc.txt +++ b/doc.txt @@ -12,7 +12,9 @@ isos documentation: 0000'7FFF'FFFF'0000 ↔ 0000'8000'0000'0000 - stack: 64KiB -- Invalid addresses -- FFFF'8000'0000'0000 ↔ FFFF'C000'0000'0000 - physical memory: 64TiB -FFFF'C000'0000'0000 ↔ FFFF'FFFF'8000'0000 - unmapped: 64TiB - 2GiB +FFFF'C000'0000'0000 ↔ FFFF'C000'0001'0000 - process information table: 64KiB, 2048 processes at most +FFFF'C000'0001'0000 ↔ FFFF'C000'0801'0000 - port information table: 128MiB, 4096 ports per process at most +FFFF'C000'0801'0000 ↔ FFFF'FFFF'8000'0000 - unmapped: 64TiB - 2GiB - 128MiB - 64KiB FFFF'FFFF'8000'0000 ↔10000'0000'0000'0000 - kernel: 2GiB --------------------------- diff --git a/kernel/src/elf64.cpp b/kernel/src/elf64.cpp index 98d47c5..79896ca 100644 --- a/kernel/src/elf64.cpp +++ b/kernel/src/elf64.cpp @@ -12,3 +12,66 @@ // not, see . #include "elf64.hpp" + +os::process os::elf::load_elf(void* start, std::size_t length, const paging::PML4T& original_PML4T) { + os::assert(length >= sizeof(os::elf::header), "Elf file isn't big enough to contain a header: there is an error."); + // TODO: Check that the elf file sections are all fully inside the file. + + // Load test-module elf file: + const os::elf::header elf_header = *(os::elf::header*)start; + + // Check if elf is valid: + os::assert(elf_header.magic[0] == '\x7f', "No elf header."); + os::assert(elf_header.magic[1] == 'E', "No elf header."); + os::assert(elf_header.magic[2] == 'L', "No elf header."); + os::assert(elf_header.magic[3] == 'F', "No elf header."); + os::assert(elf_header.bitn == 2, "Elf file not 64 bits."); + os::assert(elf_header.endianness == 1, "Elf file not little endian."); + os::assert(elf_header.type == 2, "Elf file not executable."); + os::assert(elf_header.arch == 0x3E, "Elf file not x86_64."); + + constexpr std::size_t stack_size = 16 * 0x1000 /* 64KiB */; + std::byte* const stack = (std::byte*)0x0000'8000'0000'0000 - stack_size; + os::process result = { + .PML4T = phys_ptr(os::paging::page_allocator.allocate(1).ptr.get_phys_addr()), + .rip = std::uint64_t(elf_header.entry), + .rsp = std::uint64_t(stack + stack_size) + }; + + // Copy kernel mappings to the new virtual address space. + for (size_t i = 0; i < 256; i++) { + result.PML4T->contents[256 + i] = original_PML4T.contents[256 + i]; + } + + for (std::size_t i = 0; i < elf_header.entry_count_program_header_table; i++) { + const os::elf::program_header program_header = *(os::elf::program_header*)( + reinterpret_cast(start) + elf_header.program_header_table + + i * elf_header.entry_size_program_header_table + ); + if (program_header.type != 1) { // Segment shouldn't be loaded. + os::print("Segment.\n"); + continue; + } + os::print("Segment: loadable\n"); + os::assert(0x1000 <= std::uint64_t(program_header.p_vaddr) + && std::uint64_t(program_header.p_vaddr + program_header.p_memsz) < 0x10'0000'0000, + "Program segments must be contained between 0x1000 and 0x10'0000'0000 (i.e. 64GiB)."); + + // 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); + for (std::size_t j = 0; j < 0x1000 && j < program_header.p_filesz - i * 0x1000; j++) { + page[j] = ((std::byte*)start)[program_header.p_offset + j]; + } + } + } + + // Allocate and map stack (already 0-initialised by the page allocator): + for (std::size_t i = 0; i < stack_size / 0x1000 /* 64KiB */; i++) { + os::paging::setup_page(*result.PML4T, stack + i * 0x1000, 1, 1); + } + + return result; +} diff --git a/kernel/src/elf64.hpp b/kernel/src/elf64.hpp index 697c58e..b3eaa12 100644 --- a/kernel/src/elf64.hpp +++ b/kernel/src/elf64.hpp @@ -15,12 +15,12 @@ #include #include "lib/phys_ptr.hpp" +#include "ring3.hpp" namespace os { namespace elf { struct header; struct program_header; - struct __attribute__((packed)) header { std::uint8_t magic[4]; std::uint8_t bitn; @@ -55,4 +55,6 @@ namespace os { namespace elf { std::uint64_t align; }; static_assert(sizeof(program_header) == 56); + + process load_elf(void* start, std::size_t length, const paging::PML4T& original_PML4T); } } // namespace os::elf diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 9757d4c..6684df7 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -35,8 +35,8 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr start_address = nullptr; - os::phys_ptr end_address = nullptr; + std::uint64_t start_address = 0; + std::uint64_t end_address = 0; } test_module; { struct { @@ -65,8 +65,8 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr{}: {}\n", multiboot2::modules_mod_start(it) / 0x1000 * 0x1000, multiboot2::modules_mod_end(it) / 0x1000 * 0x1000, multiboot2::modules_string(it)); - test_module.start_address = os::phys_ptr(multiboot2::modules_mod_start(it) / 0x1000 * 0x1000); - test_module.end_address = os::phys_ptr(multiboot2::modules_mod_end(it) / 0x1000 * 0x1000); // [s,e], not [s,e[ + test_module.start_address = multiboot2::modules_mod_start(it); + test_module.end_address = multiboot2::modules_mod_end(it); break; default: break; } @@ -104,23 +104,30 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr start_address; + os::phys_ptr end_address; + } test_module_block{ + os::phys_ptr(test_module.start_address / 0x1000 * 0x1000), + os::phys_ptr(test_module.end_address / 0x1000 * 0x1000) + }; // Remove module from available RAM: for (std::size_t i = 0; i < available_ram_length; i++) { - if (test_module.end_address < available_ram[i].start_address || available_ram[i].end_address < test_module.start_address) { + if (test_module_block.end_address < available_ram[i].start_address || available_ram[i].end_address < test_module_block.start_address) { continue; } - if (test_module.start_address <= available_ram[i].start_address && available_ram[i].end_address <= test_module.end_address) { + if (test_module_block.start_address <= available_ram[i].start_address && available_ram[i].end_address <= test_module_block.end_address) { available_ram[i] = available_ram[--available_ram_length]; i--; - } else if (test_module.start_address <= available_ram[i].start_address) { - available_ram[i].start_address = test_module.end_address + 1; // Since e < end_address, new start_address <= end_address. - } else if (available_ram[i].end_address <= test_module.end_address) { - available_ram[i].end_address = test_module.start_address - 1; // Since start_address < s, start_address <= new end_address. + } else if (test_module_block.start_address <= available_ram[i].start_address) { + available_ram[i].start_address = test_module_block.end_address + 1; // Since e < end_address, new start_address <= end_address. + } else if (available_ram[i].end_address <= test_module_block.end_address) { + available_ram[i].end_address = test_module_block.start_address - 1; // Since start_address < s, start_address <= new end_address. } else { os::assert(available_ram_length < 50, "Too much available RAM sections to initialise correctly. Will fix eventually, probably."); available_ram[available_ram_length] = available_ram[i]; - available_ram[i].end_address = test_module.start_address - 1; - available_ram[available_ram_length].start_address = test_module.end_address + 1; + available_ram[i].end_address = test_module_block.start_address - 1; + available_ram[available_ram_length].start_address = test_module_block.end_address + 1; available_ram_length++; } } @@ -179,53 +186,16 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr(get_base_address(PML4T.contents[0]).get_phys_addr()), .size = 1}); os::invlpg((void*)0x0); - // Load test-module elf file: - const os::elf::header elf_header = *os::phys_ptr(test_module.start_address.get_phys_addr()); - - // Check if elf is valid: - os::assert(elf_header.magic[0] == '\x7f', "No elf header."); - os::assert(elf_header.magic[1] == 'E', "No elf header."); - os::assert(elf_header.magic[2] == 'L', "No elf header."); - os::assert(elf_header.magic[3] == 'F', "No elf header."); - os::assert(elf_header.bitn == 2, "Elf file not 64 bits."); - os::assert(elf_header.endianness == 1, "Elf file not little endian."); - os::assert(elf_header.type == 2, "Elf file not executable."); - os::assert(elf_header.arch == 0x3E, "Elf file not x86_64."); - - for (std::size_t i = 0; i < elf_header.entry_count_program_header_table; i++) { - const os::elf::program_header program_header = *os::phys_ptr( - (os::phys_ptr(test_module.start_address.get_phys_addr()) + elf_header.program_header_table - + i * elf_header.entry_size_program_header_table).get_phys_addr() - ); - if (program_header.type != 1) { // Segment shouldn't be loaded. - os::print("Segment.\n"); - continue; - } - os::print("Segment: loadable\n"); - os::assert(0x1000 <= std::uint64_t(program_header.p_vaddr) - && std::uint64_t(program_header.p_vaddr + program_header.p_memsz) < 0x10'0000'0000, - "Program segments must be contained between 0x1000 and 0x10'0000'0000 (i.e. 64GiB)."); - - // Allocate memory for segment: - 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++) { - os::paging::setup_page(PML4T, program_header.p_vaddr + i * 0x1000, (program_header.flags & 2) >> 1, 1); - } - // Initialise memory for segment: - for (std::size_t i = 0; i < program_header.p_filesz; i++) { - program_header.p_vaddr[i] = os::phys_ptr(test_module.start_address.get_phys_addr())[program_header.p_offset + i]; - } - for (std::size_t i = program_header.p_filesz; i < program_header.p_memsz; i++) { - program_header.p_vaddr[i] = std::byte(0); - } + // Allocate this page so that I only ever need to update the mapping once when I create a new process or port. + { + const auto index = os::paging::calc_page_table_indices((void*)0xFFFF'C000'0000'0000).pml4e; + PML4T.contents[index] = {.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); + set_base_address(PML4T.contents[index], os::phys_ptr(PDPT_alloc.ptr.get_phys_addr())); } - // Allocate and map stack. - constexpr std::size_t stack_size = 16 * 0x1000 /* 64KiB */; - std::byte * const stack = (std::byte*)0x0000'8000'0000'0000 - stack_size; - for (std::size_t i = 0; i < stack_size / 0x1000 /* 64KiB */; i++) { - os::paging::setup_page(PML4T, stack + i * 0x1000, 1, 1); - } + auto test_module_process = + os::elf::load_elf(&*os::phys_ptr(test_module.start_address), test_module.end_address - test_module.start_address, PML4T); os::print("Loading ring 3 interrupts stack.\n"); os::set_ring0_stack(TSS, std::uint64_t(&interrupt_stack_top)); @@ -233,6 +203,13 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr(page_alloc.ptr.get_phys_addr())); invlpg(vaddr); + return (std::byte*)&*page_alloc.ptr; } namespace { @@ -97,6 +98,9 @@ void os::paging::on_all_pages(const os::paging::PML4T& PML4T, void f(page*, phys } } +void os::paging::load_pml4t(phys_ptr PML4T) { + asm volatile("mov %0, %%cr3" :: "r" (PML4T) : "memory"); +} os::paging::page one_past_end_page_for_page_allocator; os::paging::page_allocator_t os::paging::page_allocator(os::phys_ptr(reinterpret_cast(&one_past_end_page_for_page_allocator) - 0xFFFFFFFF80000000)); diff --git a/kernel/src/paging.hpp b/kernel/src/paging.hpp index 9fcb6ee..1cfb999 100644 --- a/kernel/src/paging.hpp +++ b/kernel/src/paging.hpp @@ -235,11 +235,13 @@ constexpr page_table_indices calc_page_table_indices(const void* ptr) { }; } -void setup_page(PML4T& PML4T, const void* vaddr, bool R_W, bool U_S); +std::byte* setup_page(PML4T& PML4T, const void* vaddr, bool R_W, bool U_S); // 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*, phys_ptr, std::size_t)); +void load_pml4t(phys_ptr PML4T); + class page_allocator_t; extern page_allocator_t page_allocator; diff --git a/kernel/src/ring3.cpp b/kernel/src/ring3.cpp index 589e38e..3e20646 100644 --- a/kernel/src/ring3.cpp +++ b/kernel/src/ring3.cpp @@ -62,3 +62,5 @@ extern "C" void os::syscall_print_low_mmap() { extern "C" void os::syscall_rax_error_handler() { os::assert(false, "Incorrect %rax for syscall."); } + +std::uint64_t os::current_pid; diff --git a/kernel/src/ring3.hpp b/kernel/src/ring3.hpp index eab7646..ab77686 100644 --- a/kernel/src/ring3.hpp +++ b/kernel/src/ring3.hpp @@ -15,6 +15,8 @@ #include #include +#include "lib/phys_ptr.hpp" +#include "paging.hpp" namespace os { @@ -47,4 +49,32 @@ extern "C" void syscall_rax_error_handler(); void set_ring0_stack(tss& tss, std::uint64_t stack); void enable_syscalls(); +struct process { + phys_ptr PML4T; + std::uint64_t rip; + std::uint64_t rsp; + std::uint64_t : 64; +}; +static_assert(sizeof(process) == 32); + +// (¬0);0 -> port was closed on other side, via syscall or program termination +// 0 ;0 -> port doesn't exist +struct port { + std::uint64_t other_pid; + std::uint64_t other_port; +}; +static_assert(sizeof(port) == 16); + +inline process& get_process(std::uint64_t pid) { + os::assert(1 <= pid && pid <= 2048, "Invalid pid: {}.\n", pid); + return ((process*)0xFFFF'C000'0000'0000)[pid - 1]; +} +inline port& get_port(std::uint64_t pid, std::uint64_t port) { + os::assert(1 <= pid && pid <= 2048, "Invalid pid: {}.\n", pid); + os::assert(1 <= port && port <= 4096, "Invalid port: {}.\n", pid); + return ((os::port*)0xFFFF'C000'0001'0000)[(pid - 1) * 4096 + (port - 1)]; +} + +extern std::uint64_t current_pid; + } // namespace os -- 2.47.0