From: Amelia Coutard Date: Mon, 27 Feb 2023 11:47:20 +0000 (+0100) Subject: Implemented an elf64 loader for test_module X-Git-Url: https://git.ameliathe1st.gay/?a=commitdiff_plain;h=e94956882fbc0dfa3ebd4cffbfda31b4b04e51d0;p=voyage-au-centre-des-fichiers.git Implemented an elf64 loader for test_module --- diff --git a/grub.cfg b/grub.cfg index 11f6906..f1fc76e 100644 --- a/grub.cfg +++ b/grub.cfg @@ -1,4 +1,4 @@ menuentry "Amycros" { multiboot2 /boot/kernel.elf64 - module2 /boot/test-module test-module + module2 /boot/test-module.elf64 test-module } diff --git a/kernel/src/elf64.hpp b/kernel/src/elf64.hpp index 6f70f09..17bbfa3 100644 --- a/kernel/src/elf64.hpp +++ b/kernel/src/elf64.hpp @@ -1 +1,45 @@ #pragma once + +#include +#include "lib/phys_ptr.hpp" + +namespace os { namespace elf { + struct header; + struct program_header; + + + struct __attribute__((packed)) header { + std::uint8_t magic[4]; + std::uint8_t bitn; + std::uint8_t endianness; + std::uint8_t header_version; + std::uint8_t abi; + std::uint64_t : 64; + std::uint16_t type; + std::uint16_t arch; + std::uint32_t elf_version; + void* entry; + std::uint64_t program_header_table; + std::uint64_t section_header_table; + std::uint32_t flags; + std::uint16_t header_size; + std::uint16_t entry_size_program_header_table; + std::uint16_t entry_count_program_header_table; + std::uint16_t entry_size_section_header_table; + std::uint16_t entry_count_section_header_table; + std::uint16_t index_section_names_section_header_table; + }; + static_assert(sizeof(header) == 64); + + struct __attribute__((packed)) program_header { + std::uint32_t type; + std::uint32_t flags; + std::uint64_t p_offset; + std::byte* p_vaddr; + std::uint64_t : 64; + std::uint64_t p_filesz; + std::uint64_t p_memsz; + std::uint64_t align; + }; + static_assert(sizeof(program_header) == 56); +} } // namespace os::elf diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index d07261d..1485a17 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -168,19 +168,68 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr(get_base_address(PML4T.contents[0]).get_phys_addr()), .size = 1}); os::paging::page_allocator.print_all(); - // Map test_module to virtual address 0x0000'0000'0000'1000. - { - os::phys_ptr PT {os::paging::page_allocator.allocate(1).ptr.get_phys_addr()}; - os::phys_ptr PDT {os::paging::page_allocator.allocate(1).ptr.get_phys_addr()}; - os::phys_ptr PDPT{os::paging::page_allocator.allocate(1).ptr.get_phys_addr()}; - PML4T.contents[0] = { .P = 1, .R_W = 0, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}; - PDPT->contents[0] = {.non_page = {.P = 1, .R_W = 0, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; - PDT->contents[0] = {.non_page = {.P = 1, .R_W = 0, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; - PT->contents[1] = { .P = 1, .R_W = 0, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 0}; - set_base_address(PML4T.contents[0], PDPT); - set_base_address(PDPT->contents[0], PDT); - set_base_address(PDT->contents[0], PT); - set_page_base_address(PT->contents[1], test_module.start_address); + // 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((std::uintptr_t(program_header.p_vaddr) & 0xFFF) == 0, "Program segment not 4KiB aligned."); + + // Allocate memory for segment: + std::size_t nb_pages = (program_header.p_memsz + 1023) / 1024; + for (std::size_t i = 0; i < nb_pages; i++) { + const auto indices = os::paging::calc_page_table_indices(program_header.p_vaddr + i * 0x1000); + os::assert(indices.pml4e < 256, "Userspace program must be in the lower-half of virtual memory."); + if (PML4T.contents[indices.pml4e].P == 0) { + PML4T.contents[indices.pml4e] = {.P = 1, .R_W = 0, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}; + const auto PDPT_alloc = os::paging::page_allocator.allocate(1); + 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 = 0, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; + const auto PDT_alloc = os::paging::page_allocator.allocate(1); + set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr(PDT_alloc.ptr.get_phys_addr())); + } + 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 = 0, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}}; + const auto PT_alloc = os::paging::page_allocator.allocate(1); + set_base_address(PDT.contents[indices.pde], os::phys_ptr(PT_alloc.ptr.get_phys_addr())); + } + os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]); + if (PT.contents[indices.pe].P == 0) { + PT.contents[indices.pe] = {.P = 1, .R_W = 0, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 0}; + const auto page_alloc = os::paging::page_allocator.allocate(1); + set_page_base_address(PT.contents[indices.pe], os::phys_ptr(page_alloc.ptr.get_phys_addr())); + } + } + + // 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); + } } asm volatile("invlpg (%0)" ::"r" (0x1000) : "memory"); @@ -191,7 +240,7 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr{} ({})\n", std::uint64_t(virt), std::uint64_t(phys.get_phys_addr()), size); }); - // Allow userspaaaaaaaaace in ring 3. Otherwise, we just immediately page fault. + // Allow kernel in ring 3. Otherwise, we just immediately page fault. // Will make it a module soon-ish. get_base_address(PML4T.contents[511])->contents[510].page.U_S = true; get_base_address(PML4T.contents[511])->contents[511].page.U_S = true; @@ -204,5 +253,5 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr ptr) { PE.base_address = ptr.get_phys_addr() / 0x1000ull; } +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(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), + }; +} + // 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)); diff --git a/kernel/src/ring3.S b/kernel/src/ring3.S index 48bf822..f648cf1 100644 --- a/kernel/src/ring3.S +++ b/kernel/src/ring3.S @@ -2,7 +2,7 @@ .globl ftl_to_userspace ftl_to_userspace: - mov $0x1000, %rcx + mov %rdi, %rcx mov $0x202, %r11 # EFLAGS sysretq diff --git a/kernel/src/ring3.hpp b/kernel/src/ring3.hpp index e19e354..6bb02b3 100644 --- a/kernel/src/ring3.hpp +++ b/kernel/src/ring3.hpp @@ -24,6 +24,6 @@ struct __attribute__((packed)) tss { void set_ring0_stack(tss& tss, std::uint64_t stack); extern "C" void load_tss(); void enable_syscalls(); -extern "C" void ftl_to_userspace(); +extern "C" void ftl_to_userspace(void* program); } diff --git a/test_module/module.mk b/test_module/module.mk index 54e04aa..437b5bf 100644 --- a/test_module/module.mk +++ b/test_module/module.mk @@ -8,9 +8,9 @@ SRC_DIR := test_module/src/ OUT_DIR := test_module/out/ DEP_DIR := test_module/dep/ -EXEC_NAME := test.elf64 +EXEC_NAME := test-module.elf64 -TO_ISO += isodir/boot/test-module +TO_ISO += isodir/boot/$(EXEC_NAME) TO_CLEAN += $(OUT_DIR) $(DEP_DIR) LOCAL_CXXFLAGS := $(CXXFLAGS) -O0 @@ -20,12 +20,9 @@ CPPOBJS := $(patsubst $(SRC_DIR)%,$(OUT_DIR)%.o,$(shell find $(SRC_DIR) -name '* ASMOBJS := $(patsubst $(SRC_DIR)%,$(OUT_DIR)%.o,$(shell find $(SRC_DIR) -name '*.S')) OBJS := $(CPPOBJS) $(ASMOBJS) -isodir/boot/test-module: $(OUT_DIR)$(EXEC_NAME) +isodir/boot/$(EXEC_NAME): $(OUT_DIR)$(EXEC_NAME) mkdir -p "$(@D)" - objdump -d "$<" | \ - grep ' [0-9a-e]\{6\}' | sed 's/ [^ \t]*\t//' | sed 's/\t.*//' | sed 's/[ \t]\+/ /g' | tr '\n' ' ' | \ - sed 's/ / /g' | xargs -n 1 printf '\\\\x%s\n' | xargs -n 1 printf \ - > "$@" + install -m 644 "$<" "$@" $(OUT_DIR)$(EXEC_NAME): OBJS := $(OBJS) $(OUT_DIR)$(EXEC_NAME): LDLIBS := -nostdlib -lgcc diff --git a/test_module/src/test.cpp b/test_module/src/test.cpp index c694e32..b2d8219 100644 --- a/test_module/src/test.cpp +++ b/test_module/src/test.cpp @@ -1,9 +1,13 @@ extern "C" void print(char c); -extern "C" void _start() { - const char str[4] = "AH\n"; +void printstr(const char* str) { for (int i = 0; str[i] != '\0'; i++) { print(str[i]); } +} + +extern "C" void _start() { + const char* str = "ACAB cependant.\n"; + printstr(str); while (true) {} }