]> git.ameliathe1st.gay Git - voyage-au-centre-des-fichiers.git/commitdiff
Implemented an elf64 loader for test_module
authorAmelia Coutard <eliottulio.coutard@gmail.com>
Mon, 27 Feb 2023 11:47:20 +0000 (12:47 +0100)
committerAmelia Coutard <eliottulio.coutard@gmail.com>
Mon, 27 Feb 2023 11:47:20 +0000 (12:47 +0100)
grub.cfg
kernel/src/elf64.hpp
kernel/src/kernel.cpp
kernel/src/paging.hpp
kernel/src/ring3.S
kernel/src/ring3.hpp
test_module/module.mk
test_module/src/test.cpp

index 11f69062358c89d973c414e49429ec64f048c91b..f1fc76eb2df6a2b3cc4c6b640a87cefa8b49c90e 100644 (file)
--- 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
 }
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..17bbfa3317f943f9a0dba36c5cd40bafcb366680 100644 (file)
@@ -1 +1,45 @@
 #pragma once
+
+#include <cstdint>
+#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
index d07261df48aa898ad4e5a44392253232b7c374d5..1485a17535299bf4181b6bbbef475fc646fab848 100644 (file)
@@ -168,19 +168,68 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
        PML4T.contents[0].P = false;
        os::paging::page_allocator.deallocate({.ptr = os::phys_ptr<os::paging::page>(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<os::paging::PT>   PT  {os::paging::page_allocator.allocate(1).ptr.get_phys_addr()};
-               os::phys_ptr<os::paging::PDT>  PDT {os::paging::page_allocator.allocate(1).ptr.get_phys_addr()};
-               os::phys_ptr<os::paging::PDPT> 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<os::elf::header>(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::elf::program_header>(
+                       (os::phys_ptr<std::byte>(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<os::paging::PDPT>(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<os::paging::PDT>(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<os::paging::PT>(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<os::paging::page>(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<std::byte>(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<const multiboot2::info_s
                os::print("{}->{} ({})\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<const multiboot2::info_s
        os::print("Enabling syscalls.\n");
        os::enable_syscalls();
        os::print("Moving to ring 3.\n");
-       os::ftl_to_userspace();
+       os::ftl_to_userspace(elf_header.entry);
 }
index 5a2c809040a8e0a7ec800532368d8b689d010d87..677caa2f055b2b24b42b40d0d85798cae20176cd 100644 (file)
@@ -207,6 +207,21 @@ inline void set_page_base_address(PE& PE, phys_ptr<page> 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<page>, std::size_t));
 
index 48bf822abdfef43d1d925da252697918badbaa09..f648cf1a91cc518f0eb28d373b7b46d53fcbc599 100644 (file)
@@ -2,7 +2,7 @@
 
 .globl ftl_to_userspace
 ftl_to_userspace:
-       mov $0x1000, %rcx
+       mov %rdi, %rcx
        mov $0x202, %r11 # EFLAGS
        sysretq
 
index e19e3540b328b1cddba52b0b06ab096271afd02b..6bb02b3f811af82e8d4710908c15e5d5114dd516 100644 (file)
@@ -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);
 
 }
index 54e04aaae20693dba2810a1a331cf3b5fbec0163..437b5bf4802323b79a047c54b6f5d2c474df539a 100644 (file)
@@ -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
index c694e32a1e808253b6705c2757ae8a2c499bdd8f..b2d8219d5f2d207f22770764ab80c2be973ed9e9 100644 (file)
@@ -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) {}
 }