]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
x86: stabilize initrd/PMM and ring3 ELF bring-up
authorTulio A M Mendes <[email protected]>
Fri, 6 Feb 2026 18:09:23 +0000 (15:09 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 6 Feb 2026 18:09:23 +0000 (15:09 -0300)
17 files changed:
.gitignore
Makefile
include/arch/x86/usermode.h [new file with mode: 0644]
include/elf.h [new file with mode: 0644]
iso/boot/grub/grub.cfg
src/arch/x86/boot.S
src/arch/x86/gdt.c
src/arch/x86/idt.c
src/arch/x86/usermode.c
src/drivers/initrd.c
src/kernel/elf.c [new file with mode: 0644]
src/kernel/main.c
src/kernel/scheduler.c
src/mm/pmm.c
tools/mkinitrd.c
user/init.c [new file with mode: 0644]
user/linker.ld [new file with mode: 0644]

index aa39258eb16d3017b3aca46f28ba4b2bdb86ec60..da6084d4336e5a51dc86accf88858be0a8e9f248 100644 (file)
@@ -5,6 +5,7 @@ build/
 *.iso
 *.img
 *.log
+*.elf
 
 # ISO staging: keep config, ignore generated kernel binaries
 iso/boot/*.bin
@@ -13,10 +14,15 @@ iso/boot/*.bin
 compile_commands.json
 clang-tidy.txt
 cppcheck.txt
+cppcheck2.txt
+cppcheck3.txt
 scanbuild-out/
 gcc-analyzer.txt
 splint.txt
 
+# Tools (built binaries)
+tools/mkinitrd
+
 # Temporary folders
 iso_root/
 isodir/
index 878c26d761d818a2d9f0f0167fcf059e28d450d7..2faa327b37df25ba6baed18e09fe0feb4889d2ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,10 @@ ifeq ($(ARCH),x86)
 
     ASM_SOURCES := $(wildcard $(SRC_DIR)/arch/x86/*.S)
     C_SOURCES += $(wildcard $(SRC_DIR)/arch/x86/*.c)
+
+    USER_ELF := user/init.elf
+    INITRD_IMG := initrd.img
+    MKINITRD := tools/mkinitrd
 endif
 
 # --- ARM64 Configuration ---
@@ -85,6 +89,15 @@ endif
 OBJ := $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES))
 OBJ += $(patsubst $(SRC_DIR)/%.S, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
 
+QEMU_DFLAGS :=
+ifneq ($(QEMU_DEBUG),)
+QEMU_DFLAGS := -d guest_errors,cpu_reset -D qemu.log
+endif
+
+ifneq ($(QEMU_INT),)
+QEMU_DFLAGS := $(QEMU_DFLAGS) -d int
+endif
+
 BOOT_OBJ := $(BUILD_DIR)/arch/x86/boot.o
 KERNEL_OBJ := $(filter-out $(BOOT_OBJ), $(OBJ))
 
@@ -94,17 +107,27 @@ $(KERNEL_NAME): $(OBJ)
        @echo "  LD      $@"
        @$(LD) $(LDFLAGS) -n -o $@ $(BOOT_OBJ) $(KERNEL_OBJ)
 
-iso: $(KERNEL_NAME)
+iso: $(KERNEL_NAME) $(INITRD_IMG)
        @mkdir -p iso/boot
        @cp -f $(KERNEL_NAME) iso/boot/$(KERNEL_NAME)
+       @cp -f $(INITRD_IMG) iso/boot/$(INITRD_IMG)
        @echo "  GRUB-MKRESCUE  adros-$(ARCH).iso"
        @grub-mkrescue -o adros-$(ARCH).iso iso > /dev/null
 
+$(MKINITRD): tools/mkinitrd.c
+       @gcc tools/mkinitrd.c -o $(MKINITRD)
+
+$(USER_ELF): user/init.c user/linker.ld
+       @i686-elf-gcc -m32 -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/linker.ld -o $(USER_ELF) user/init.c
+
+$(INITRD_IMG): $(MKINITRD) $(USER_ELF)
+       @./$(MKINITRD) $(INITRD_IMG) $(USER_ELF)
+
 run: iso
        @rm -f serial.log qemu.log
        @qemu-system-i386 -boot d -cdrom adros-$(ARCH).iso -m 128M -display none \
                -serial file:serial.log -monitor none -no-reboot -no-shutdown \
-               $(if $(QEMU_DEBUG),-d guest_errors -D qemu.log,)
+               $(QEMU_DFLAGS)
 
 $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
        @mkdir -p $(dir $@)
diff --git a/include/arch/x86/usermode.h b/include/arch/x86/usermode.h
new file mode 100644 (file)
index 0000000..64fcd74
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef ARCH_X86_USERMODE_H
+#define ARCH_X86_USERMODE_H
+
+#include <stdint.h>
+
+#if defined(__i386__)
+__attribute__((noreturn)) void x86_enter_usermode(uintptr_t user_eip, uintptr_t user_esp);
+#endif
+
+#endif
diff --git a/include/elf.h b/include/elf.h
new file mode 100644 (file)
index 0000000..55d998a
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef ELF_H
+#define ELF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define EI_NIDENT 16
+
+typedef struct {
+    unsigned char e_ident[EI_NIDENT];
+    uint16_t e_type;
+    uint16_t e_machine;
+    uint32_t e_version;
+    uint32_t e_entry;
+    uint32_t e_phoff;
+    uint32_t e_shoff;
+    uint32_t e_flags;
+    uint16_t e_ehsize;
+    uint16_t e_phentsize;
+    uint16_t e_phnum;
+    uint16_t e_shentsize;
+    uint16_t e_shnum;
+    uint16_t e_shstrndx;
+} elf32_ehdr_t;
+
+typedef struct {
+    uint32_t p_type;
+    uint32_t p_offset;
+    uint32_t p_vaddr;
+    uint32_t p_paddr;
+    uint32_t p_filesz;
+    uint32_t p_memsz;
+    uint32_t p_flags;
+    uint32_t p_align;
+} elf32_phdr_t;
+
+#define ELF_MAGIC0 0x7F
+#define ELF_MAGIC1 'E'
+#define ELF_MAGIC2 'L'
+#define ELF_MAGIC3 'F'
+
+#define ELFCLASS32 1
+#define ELFDATA2LSB 1
+
+#define ET_EXEC 2
+#define EM_386 3
+
+#define PT_LOAD 1
+
+#define PF_X 0x1
+#define PF_W 0x2
+#define PF_R 0x4
+
+int elf32_load_user_from_initrd(const char* filename, uintptr_t* entry_out, uintptr_t* user_stack_top_out);
+
+#endif
index ca6a033433d3681aefb2df41700838d1c849a289..fd6d94399350b91dff31d59fd4c4a45b2a21240e 100644 (file)
@@ -1,11 +1,18 @@
 set timeout=5
-set default=0
+set default=1
  
 #serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
 #terminal_input serial
 #terminal_output serial
  
 menuentry "AdrOS (x86)" {
+  multiboot2 /boot/adros-x86.bin
+  module2 /boot/initrd.img
+  boot
+}
+
+menuentry "AdrOS (x86) - ring3 test" {
   multiboot2 /boot/adros-x86.bin ring3
+  module2 /boot/initrd.img
   boot
 }
index 7f06759c3a664185c585d9e76816234623daaf8b..f8aa345dcbb1129d950d9b284ffd74993ea6bf3b 100644 (file)
@@ -187,6 +187,7 @@ arch_boot_args:
 .align 16
 stack_bottom:
     .skip 16384
+.global stack_top
 stack_top:
 
 .section .note.GNU-stack,"",@progbits
index 79f1a23d72b1df5cd57a0fbfcda241dfacaa68d5..a4fe0f4f5c42324efce259d5ae948e082e4b4a17 100644 (file)
@@ -1,6 +1,7 @@
 #include "gdt.h"
 
 #include "uart_console.h"
+ #include "utils.h"
 
 struct gdt_entry {
     uint16_t limit_low;
index 55c9a807c6fac8a620cb4932f3a693c12598a581..9db3e068bc9876ebb6a5fa8fbb4068dddd01eb5d 100644 (file)
@@ -86,7 +86,7 @@ void idt_init(void) {
     idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E);
     idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E);
     idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E);
-    idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E);
+    idt_set_gate(3, (uint32_t)isr3, 0x08, 0xEE);
     idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E);
     idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E);
     idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E);
index 58a8acdfe2a373e27e34b254cdccecb868fdfe14..987e92684cd700b8c1b8c0f2d55c7cac2a1fa4d3 100644 (file)
@@ -5,6 +5,7 @@
 #include "vmm.h"
 #include "uart_console.h"
 #include "utils.h"
+ #include "arch/x86/usermode.h"
 
 #if defined(__i386__)
 
@@ -69,26 +70,27 @@ static void* pmm_alloc_page_low_16mb(void) {
     return NULL;
 }
 
-__attribute__((noreturn)) static void enter_usermode(uintptr_t user_eip, uintptr_t user_esp) {
+__attribute__((noreturn)) void x86_enter_usermode(uintptr_t user_eip, uintptr_t user_esp) {
+    uart_print("[USER] enter ring3 eip=");
+    char tmp[16];
+    itoa_hex((uint32_t)user_eip, tmp);
+    uart_print(tmp);
+    uart_print(" esp=");
+    itoa_hex((uint32_t)user_esp, tmp);
+    uart_print(tmp);
+    uart_print("\n");
+
     __asm__ volatile(
         "cli\n"
-        "mov $0x23, %%ax\n"
-        "mov %%ax, %%ds\n"
-        "mov %%ax, %%es\n"
-        "mov %%ax, %%fs\n"
-        "mov %%ax, %%gs\n"
         "pushl $0x23\n"         /* ss */
         "pushl %[esp]\n"        /* esp */
-        "pushfl\n"
-        "popl %%eax\n"
-        "orl $0x200, %%eax\n"   /* IF=1 */
-        "pushl %%eax\n"
+        "pushl $0x202\n"        /* eflags: IF=1 */
         "pushl $0x1B\n"         /* cs */
         "pushl %[eip]\n"        /* eip */
         "iret\n"
         :
         : [eip] "r"(user_eip), [esp] "r"(user_esp)
-        : "eax", "memory"
+        : "memory"
     );
 
     __builtin_unreachable();
@@ -229,7 +231,7 @@ void x86_usermode_test_start(void) {
     memcpy((void*)((uintptr_t)code_phys + 0x300), "Hello from ring3!\n", msg_len);
 
     uintptr_t user_esp = user_stack_vaddr + 4096;
-    enter_usermode(user_code_vaddr, user_esp);
+    x86_enter_usermode(user_code_vaddr, user_esp);
 }
 
 #endif
index c4650338c7488d2bd6c594a8d3899e121c45cd79..aa545bd41cc00014e5068a223f493599b11b49c4 100644 (file)
@@ -58,8 +58,6 @@ fs_node_t* initrd_init(uint32_t location) {
     root_nodes = (fs_node_t*)kmalloc(sizeof(fs_node_t) * n_root_nodes);
     
     for (int i = 0; i < n_root_nodes; i++) {
-        file_headers[i].offset += location; // Fixup offset to be absolute address
-        
         strcpy(root_nodes[i].name, file_headers[i].name);
         root_nodes[i].inode = i;
         root_nodes[i].length = file_headers[i].length;
diff --git a/src/kernel/elf.c b/src/kernel/elf.c
new file mode 100644 (file)
index 0000000..2f6adc5
--- /dev/null
@@ -0,0 +1,183 @@
+#include "elf.h"
+
+#include "fs.h"
+#include "heap.h"
+#include "pmm.h"
+#include "uart_console.h"
+#include "utils.h"
+#include "vmm.h"
+
+#include <stdint.h>
+
+#if defined(__i386__)
+#define X86_KERNEL_VIRT_BASE 0xC0000000U
+
+static void* pmm_alloc_page_low_16mb(void) {
+    for (int tries = 0; tries < 4096; tries++) {
+        void* p = pmm_alloc_page();
+        if (!p) return NULL;
+        if ((uintptr_t)p < 0x01000000U) {
+            return p;
+        }
+        pmm_free_page(p);
+    }
+    return NULL;
+}
+
+static int elf32_validate(const elf32_ehdr_t* eh, size_t file_len) {
+    if (!eh) return -1;
+    if (file_len < sizeof(*eh)) return -1;
+
+    if (eh->e_ident[0] != ELF_MAGIC0 ||
+        eh->e_ident[1] != ELF_MAGIC1 ||
+        eh->e_ident[2] != ELF_MAGIC2 ||
+        eh->e_ident[3] != ELF_MAGIC3) {
+        return -1;
+    }
+    if (eh->e_ident[4] != ELFCLASS32) return -1;
+    if (eh->e_ident[5] != ELFDATA2LSB) return -1;
+
+    if (eh->e_type != ET_EXEC) return -1;
+    if (eh->e_machine != EM_386) return -1;
+
+    if (eh->e_phentsize != sizeof(elf32_phdr_t)) return -1;
+    if (eh->e_phnum == 0) return -1;
+
+    uint32_t ph_end = eh->e_phoff + (uint32_t)eh->e_phnum * (uint32_t)sizeof(elf32_phdr_t);
+    if (ph_end < eh->e_phoff) return -1;
+    if (ph_end > file_len) return -1;
+
+    if (eh->e_entry == 0) return -1;
+    if (eh->e_entry >= X86_KERNEL_VIRT_BASE) return -1;
+
+    return 0;
+}
+
+static int elf32_map_user_range(uintptr_t vaddr, size_t len, uint32_t flags) {
+    if (len == 0) return 0;
+    if (vaddr == 0) return -1;
+    if (vaddr >= X86_KERNEL_VIRT_BASE) return -1;
+
+    uintptr_t end = vaddr + len - 1;
+    if (end < vaddr) return -1;
+    if (end >= X86_KERNEL_VIRT_BASE) return -1;
+
+    uintptr_t start_page = vaddr & ~(uintptr_t)0xFFF;
+    uintptr_t end_page = end & ~(uintptr_t)0xFFF;
+
+    for (uintptr_t va = start_page;; va += 0x1000) {
+        void* phys = pmm_alloc_page_low_16mb();
+        if (!phys) return -1;
+
+        vmm_map_page((uint64_t)(uintptr_t)phys, (uint64_t)va, flags | VMM_FLAG_PRESENT | VMM_FLAG_USER);
+
+        if (va == end_page) break;
+    }
+
+    return 0;
+}
+
+int elf32_load_user_from_initrd(const char* filename, uintptr_t* entry_out, uintptr_t* user_stack_top_out) {
+    if (!filename || !entry_out || !user_stack_top_out) return -1;
+    if (!fs_root) return -1;
+
+    fs_node_t* node = fs_root->finddir ? fs_root->finddir(fs_root, (char*)filename) : NULL;
+    if (!node) {
+        uart_print("[ELF] file not found: ");
+        uart_print(filename);
+        uart_print("\n");
+        return -1;
+    }
+
+    uint32_t file_len = node->length;
+    if (file_len < sizeof(elf32_ehdr_t)) return -1;
+
+    uint8_t* file = (uint8_t*)kmalloc(file_len);
+    if (!file) return -1;
+
+    uint32_t rd = vfs_read(node, 0, file_len, file);
+    if (rd != file_len) {
+        kfree(file);
+        return -1;
+    }
+
+    const elf32_ehdr_t* eh = (const elf32_ehdr_t*)file;
+    if (elf32_validate(eh, file_len) < 0) {
+        uart_print("[ELF] invalid ELF header\n");
+        kfree(file);
+        return -1;
+    }
+
+    const elf32_phdr_t* ph = (const elf32_phdr_t*)(file + eh->e_phoff);
+
+    for (uint16_t i = 0; i < eh->e_phnum; i++) {
+        if (ph[i].p_type != PT_LOAD) continue;
+
+        if (ph[i].p_memsz == 0) continue;
+        if (ph[i].p_vaddr == 0) {
+            uart_print("[ELF] PT_LOAD with vaddr=0 rejected\n");
+            kfree(file);
+            return -1;
+        }
+        if (ph[i].p_vaddr >= X86_KERNEL_VIRT_BASE) {
+            uart_print("[ELF] PT_LOAD in kernel range rejected\n");
+            kfree(file);
+            return -1;
+        }
+
+        uint32_t seg_end = ph[i].p_vaddr + ph[i].p_memsz;
+        if (seg_end < ph[i].p_vaddr) {
+            kfree(file);
+            return -1;
+        }
+        if (seg_end >= X86_KERNEL_VIRT_BASE) {
+            kfree(file);
+            return -1;
+        }
+
+        if ((uint64_t)ph[i].p_offset + (uint64_t)ph[i].p_filesz > (uint64_t)file_len) {
+            uart_print("[ELF] segment outside file\n");
+            kfree(file);
+            return -1;
+        }
+
+        const uint32_t map_flags = VMM_FLAG_RW;
+
+        if (elf32_map_user_range((uintptr_t)ph[i].p_vaddr, (size_t)ph[i].p_memsz, map_flags) < 0) {
+            uart_print("[ELF] OOM mapping user segment\n");
+            kfree(file);
+            return -1;
+        }
+
+        if (ph[i].p_filesz) {
+            memcpy((void*)(uintptr_t)ph[i].p_vaddr, file + ph[i].p_offset, ph[i].p_filesz);
+        }
+
+        if (ph[i].p_memsz > ph[i].p_filesz) {
+            memset((void*)(uintptr_t)(ph[i].p_vaddr + ph[i].p_filesz), 0, ph[i].p_memsz - ph[i].p_filesz);
+        }
+    }
+
+    const uintptr_t user_stack_base = 0x00800000U;
+    const size_t user_stack_size = 0x1000;
+
+    if (elf32_map_user_range(user_stack_base, user_stack_size, VMM_FLAG_RW) < 0) {
+        uart_print("[ELF] OOM mapping user stack\n");
+        kfree(file);
+        return -1;
+    }
+
+    *entry_out = (uintptr_t)eh->e_entry;
+    *user_stack_top_out = user_stack_base + user_stack_size;
+
+    kfree(file);
+    return 0;
+}
+#else
+int elf32_load_user_from_initrd(const char* filename, uintptr_t* entry_out, uintptr_t* user_stack_top_out) {
+    (void)filename;
+    (void)entry_out;
+    (void)user_stack_top_out;
+    return -1;
+}
+#endif
index 08b8f374aac1aa81ae4387d389b294e448b3f13e..bab7a11103e84adde30e4b2744bee24436b1bb63 100644 (file)
@@ -14,6 +14,8 @@
 #include "multiboot2.h"
 #include "initrd.h"
 #include "fs.h"
+ #include "elf.h"
+ #include "uaccess.h"
 
 #include "kernel/boot_info.h"
 
 
 #include "hal/cpu.h"
 
+#if defined(__i386__)
+#include "arch/x86/usermode.h"
+#endif
+
 #if defined(__i386__)
 extern void x86_usermode_test_start(void);
 
+static uint8_t ring0_trap_stack[16384] __attribute__((aligned(16)));
+
 static int cmdline_has_token(const char* cmdline, const char* token) {
     if (!cmdline || !token) return 0;
 
@@ -90,12 +98,6 @@ void kernel_main(const struct boot_info* bi) {
 
     hal_cpu_enable_interrupts();
 
-#if defined(__i386__)
-    if (bi && cmdline_has_token(bi->cmdline, "ring3")) {
-        x86_usermode_test_start();
-    }
-#endif
-
     // 9. Load InitRD (if available)
     if (bi && bi->initrd_start) {
         const uintptr_t initrd_virt_base = 0xE0000000U;
@@ -119,6 +121,29 @@ void kernel_main(const struct boot_info* bi) {
         uintptr_t initrd_virt = initrd_virt_base + ((uintptr_t)bi->initrd_start - phys_start);
         fs_root = initrd_init((uint32_t)initrd_virt);
     }
+
+#if defined(__i386__)
+    if (fs_root) {
+        uintptr_t entry = 0;
+        uintptr_t user_sp = 0;
+        if (elf32_load_user_from_initrd("init.elf", &entry, &user_sp) == 0) {
+            uart_print("[ELF] starting init.elf\n");
+
+            uart_print("[ELF] user_range_ok(entry)=");
+            uart_put_char(user_range_ok((const void*)entry, 1) ? '1' : '0');
+            uart_print(" user_range_ok(stack)=");
+            uart_put_char(user_range_ok((const void*)(user_sp - 16), 16) ? '1' : '0');
+            uart_print("\n");
+
+            hal_cpu_set_kernel_stack((uintptr_t)&ring0_trap_stack[sizeof(ring0_trap_stack)]);
+            x86_enter_usermode(entry, user_sp);
+        }
+    }
+
+    if (bi && cmdline_has_token(bi->cmdline, "ring3")) {
+        x86_usermode_test_start();
+    }
+#endif
     
     // Start Shell as the main interaction loop
     shell_init();
index 9a5b43905812f7ccb6a2489b42abe9d561b0f8a2..59e7e62aea7e6791c58cd54dc33312107aa03845 100644 (file)
@@ -41,6 +41,7 @@ void process_init(void) {
         spin_unlock_irqrestore(&sched_lock, flags);
         uart_print("[SCHED] OOM allocating kernel process struct.\n");
         for(;;) hal_cpu_idle();
+        __builtin_unreachable();
     }
     
     kernel_proc->pid = 0;
index 8bd4547d2485ba742bfb603bde21779efe297205..4b6ad23593a3d502e3acfc3367518ea3ee7671ed 100644 (file)
@@ -254,17 +254,48 @@ void pmm_init(void* boot_info) {
     }
 #endif
 
-    uint64_t kernel_size = phys_end - phys_start;
-    
-    pmm_mark_region(phys_start, kernel_size, 1); // Mark Used
+    uint64_t phys_start_aligned = align_down(phys_start, PAGE_SIZE);
+    uint64_t phys_end_aligned = align_up(phys_end, PAGE_SIZE);
+    if (phys_end_aligned < phys_start_aligned) {
+        phys_end_aligned = phys_start_aligned;
+    }
+    uint64_t kernel_size = phys_end_aligned - phys_start_aligned;
 
-    // 3. Protect Multiboot info (if x86)
+    pmm_mark_region(phys_start_aligned, kernel_size, 1); // Mark Used
+
+#if defined(__i386__) || defined(__x86_64__)
+    // 3. Protect Multiboot2 modules (e.g. initrd)
+    // The initrd is loaded by GRUB into physical memory. If we don't reserve it,
+    // the PMM may allocate those frames and overwrite the initrd header/data.
     if (boot_info) {
+        struct multiboot_tag *tag;
+        for (tag = (struct multiboot_tag *)((uint8_t *)boot_info + 8);
+             tag->type != MULTIBOOT_TAG_TYPE_END;
+             tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7)))
+        {
+            if (tag->type == MULTIBOOT_TAG_TYPE_MODULE) {
+                struct multiboot_tag_module* mod = (struct multiboot_tag_module*)tag;
+                uint64_t mod_start = (uint64_t)mod->mod_start;
+                uint64_t mod_end = (uint64_t)mod->mod_end;
+                if (mod_end < mod_start) mod_end = mod_start;
+
+                uint64_t mod_start_aligned = align_down(mod_start, PAGE_SIZE);
+                uint64_t mod_end_aligned = align_up(mod_end, PAGE_SIZE);
+                if (mod_end_aligned < mod_start_aligned) {
+                    mod_end_aligned = mod_start_aligned;
+                }
+
+                pmm_mark_region(mod_start_aligned, mod_end_aligned - mod_start_aligned, 1);
+            }
+        }
+
+        // 4. Protect Multiboot info (if x86)
         uintptr_t bi_ptr = (uintptr_t)boot_info;
         if (bi_ptr < 0xC0000000U) {
             pmm_mark_region((uint64_t)bi_ptr, 4096, 1); // Protect at least 1 page
         }
     }
+#endif
 
     uart_print("[PMM] Initialized.\n");
 }
index 98eb13f2dd5febae99e23073e2cf81b2c2c3bb17..af062e589a3d7bca70a7e3469e82651ed3d77832 100644 (file)
@@ -28,11 +28,16 @@ int main(int argc, char **argv) {
     // Prepare headers
     for(int i = 0; i < nheader; i++) {
         printf("Adding: %s\n", argv[i+2]);
-        strcpy(headers[i].name, argv[i+2]); // Warning: Buffer overflow unsafe, good enough for tool
+
+        const char* in = argv[i+2];
+        const char* base = strrchr(in, '/');
+        base = base ? (base + 1) : in;
+
+        strcpy(headers[i].name, base); // Warning: Buffer overflow unsafe, good enough for tool
         headers[i].offset = data_offset;
         headers[i].magic = 0xBF;
         
-        FILE *stream = fopen(argv[i+2], "r");
+        FILE *stream = fopen(argv[i+2], "rb");
         if(!stream) {
             printf("Error opening file: %s\n", argv[i+2]);
             return 1;
@@ -43,7 +48,7 @@ int main(int argc, char **argv) {
         fclose(stream);
     }
     
-    FILE *wstream = fopen(argv[1], "w");
+    FILE *wstream = fopen(argv[1], "wb");
     if(!wstream) {
         printf("Error opening output: %s\n", argv[1]);
         return 1;
@@ -56,7 +61,7 @@ int main(int argc, char **argv) {
     
     // Write data
     for(int i = 0; i < nheader; i++) {
-        FILE *stream = fopen(argv[i+2], "r");
+        FILE *stream = fopen(argv[i+2], "rb");
         unsigned char *buf = (unsigned char *)malloc(headers[i].length);
         fread(buf, 1, headers[i].length, stream);
         fwrite(buf, 1, headers[i].length, wstream);
diff --git a/user/init.c b/user/init.c
new file mode 100644 (file)
index 0000000..7178e64
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdint.h>
+
+enum {
+    SYSCALL_WRITE = 1,
+    SYSCALL_EXIT  = 2,
+};
+
+static int sys_write(int fd, const void* buf, uint32_t len) {
+    int ret;
+    __asm__ volatile(
+        "int $0x80"
+        : "=a"(ret)
+        : "a"(SYSCALL_WRITE), "b"(fd), "c"(buf), "d"(len)
+        : "memory"
+    );
+    return ret;
+}
+
+__attribute__((noreturn)) static void sys_exit(int code) {
+    (void)code;
+    __asm__ volatile(
+        "int $0x80\n"
+        "1: jmp 1b\n"
+        :
+        : "a"(SYSCALL_EXIT)
+        : "memory"
+    );
+    __builtin_unreachable();
+}
+
+void _start(void) {
+    __asm__ volatile(
+        "mov $0x23, %ax\n"
+        "mov %ax, %ds\n"
+        "mov %ax, %es\n"
+        "mov %ax, %fs\n"
+        "mov %ax, %gs\n"
+    );
+
+    static const char msg[] = "[init] hello from init.elf\n";
+    (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+    sys_exit(0);
+}
diff --git a/user/linker.ld b/user/linker.ld
new file mode 100644 (file)
index 0000000..85b35b6
--- /dev/null
@@ -0,0 +1,28 @@
+ENTRY(_start)
+
+PHDRS
+{
+    text PT_LOAD FLAGS(7);
+}
+
+SECTIONS
+{
+    . = 0x00400000;
+
+    .text : {
+        *(.text*)
+    } :text
+
+    .rodata : {
+        *(.rodata*)
+    } :text
+
+    .data : {
+        *(.data*)
+    } :text
+
+    .bss : {
+        *(.bss*)
+        *(COMMON)
+    } :text
+}