From 70b9c5cbf3459f034b42806a4cf995bd5fabe7b9 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Fri, 6 Feb 2026 15:09:23 -0300 Subject: [PATCH] x86: stabilize initrd/PMM and ring3 ELF bring-up --- .gitignore | 6 ++ Makefile | 27 +++++- include/arch/x86/usermode.h | 10 ++ include/elf.h | 56 +++++++++++ iso/boot/grub/grub.cfg | 9 +- src/arch/x86/boot.S | 1 + src/arch/x86/gdt.c | 1 + src/arch/x86/idt.c | 2 +- src/arch/x86/usermode.c | 26 ++--- src/drivers/initrd.c | 2 - src/kernel/elf.c | 183 ++++++++++++++++++++++++++++++++++++ src/kernel/main.c | 37 ++++++-- src/kernel/scheduler.c | 1 + src/mm/pmm.c | 39 +++++++- tools/mkinitrd.c | 13 ++- user/init.c | 43 +++++++++ user/linker.ld | 28 ++++++ 17 files changed, 452 insertions(+), 32 deletions(-) create mode 100644 include/arch/x86/usermode.h create mode 100644 include/elf.h create mode 100644 src/kernel/elf.c create mode 100644 user/init.c create mode 100644 user/linker.ld diff --git a/.gitignore b/.gitignore index aa39258..da6084d 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/Makefile b/Makefile index 878c26d..2faa327 100644 --- 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 index 0000000..64fcd74 --- /dev/null +++ b/include/arch/x86/usermode.h @@ -0,0 +1,10 @@ +#ifndef ARCH_X86_USERMODE_H +#define ARCH_X86_USERMODE_H + +#include + +#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 index 0000000..55d998a --- /dev/null +++ b/include/elf.h @@ -0,0 +1,56 @@ +#ifndef ELF_H +#define ELF_H + +#include +#include + +#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 diff --git a/iso/boot/grub/grub.cfg b/iso/boot/grub/grub.cfg index ca6a033..fd6d943 100644 --- a/iso/boot/grub/grub.cfg +++ b/iso/boot/grub/grub.cfg @@ -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 } diff --git a/src/arch/x86/boot.S b/src/arch/x86/boot.S index 7f06759..f8aa345 100644 --- a/src/arch/x86/boot.S +++ b/src/arch/x86/boot.S @@ -187,6 +187,7 @@ arch_boot_args: .align 16 stack_bottom: .skip 16384 +.global stack_top stack_top: .section .note.GNU-stack,"",@progbits diff --git a/src/arch/x86/gdt.c b/src/arch/x86/gdt.c index 79f1a23..a4fe0f4 100644 --- a/src/arch/x86/gdt.c +++ b/src/arch/x86/gdt.c @@ -1,6 +1,7 @@ #include "gdt.h" #include "uart_console.h" + #include "utils.h" struct gdt_entry { uint16_t limit_low; diff --git a/src/arch/x86/idt.c b/src/arch/x86/idt.c index 55c9a80..9db3e06 100644 --- a/src/arch/x86/idt.c +++ b/src/arch/x86/idt.c @@ -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); diff --git a/src/arch/x86/usermode.c b/src/arch/x86/usermode.c index 58a8acd..987e926 100644 --- a/src/arch/x86/usermode.c +++ b/src/arch/x86/usermode.c @@ -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 diff --git a/src/drivers/initrd.c b/src/drivers/initrd.c index c465033..aa545bd 100644 --- a/src/drivers/initrd.c +++ b/src/drivers/initrd.c @@ -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 index 0000000..2f6adc5 --- /dev/null +++ b/src/kernel/elf.c @@ -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 + +#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 diff --git a/src/kernel/main.c b/src/kernel/main.c index 08b8f37..bab7a11 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -14,6 +14,8 @@ #include "multiboot2.h" #include "initrd.h" #include "fs.h" + #include "elf.h" + #include "uaccess.h" #include "kernel/boot_info.h" @@ -23,9 +25,15 @@ #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(); diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index 9a5b439..59e7e62 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -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; diff --git a/src/mm/pmm.c b/src/mm/pmm.c index 8bd4547..4b6ad23 100644 --- a/src/mm/pmm.c +++ b/src/mm/pmm.c @@ -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"); } diff --git a/tools/mkinitrd.c b/tools/mkinitrd.c index 98eb13f..af062e5 100644 --- a/tools/mkinitrd.c +++ b/tools/mkinitrd.c @@ -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 index 0000000..7178e64 --- /dev/null +++ b/user/init.c @@ -0,0 +1,43 @@ +#include + +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 index 0000000..85b35b6 --- /dev/null +++ b/user/linker.ld @@ -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 +} -- 2.43.0