Browse Source

feat(syscall): impl. exec() to load elf files

greatbridf 2 years ago
parent
commit
34b3bf7644

+ 8 - 7
CMakeLists.txt

@@ -44,8 +44,6 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O")
 endif()
 
-include_directories(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/user-space-program/build)
-
 set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/kernel_main.c
                         src/kernel/errno.c
@@ -64,6 +62,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/kernel/event/event.cpp
                         src/types/bitmap.c
                         src/types/buffer.c
+                        src/types/elf.cpp
                         include/asm/boot.h
                         include/asm/port_io.h
                         include/asm/sys.h
@@ -88,6 +87,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/kernel/input/input_event.h
                         include/types/bitmap.h
                         include/types/buffer.h
+                        include/types/elf.hpp
                         include/types/hash_map.hpp
                         include/types/types.h
                         include/types/size.h
@@ -111,9 +111,6 @@ add_custom_command(OUTPUT extracted_kernel_main
 add_custom_target(user_space_programs
     COMMAND cp ${CMAKE_SOURCE_DIR}/user-space-program/Makefile.src ${CMAKE_SOURCE_DIR}/user-space-program/Makefile
     COMMAND make -C ${CMAKE_SOURCE_DIR}/user-space-program CROSS_COMPILE=${TOOLCHAIN_PATH_AND_PREFIX} all
-    COMMAND mkdir -p ${CMAKE_SOURCE_DIR}/user-space-program/build
-    COMMAND rm -f ${CMAKE_SOURCE_DIR}/user-space-program/build/*
-    COMMAND cp ${CMAKE_SOURCE_DIR}/user-space-program/*.res ${CMAKE_SOURCE_DIR}/user-space-program/build
 )
 
 add_custom_target(kernel.out
@@ -121,7 +118,7 @@ add_custom_target(kernel.out
     DEPENDS extracted_kernel_main
     DEPENDS user_space_programs
     DEPENDS ${CMAKE_SOURCE_DIR}/src/kernel.ld
-    COMMAND ${CMAKE_LINKER} -T ${CMAKE_SOURCE_DIR}/src/kernel.ld ${EXTRACT_DIR}/*.o ${CMAKE_SOURCE_DIR}/user-space-program/user.sym
+    COMMAND ${CMAKE_LINKER} -T ${CMAKE_SOURCE_DIR}/src/kernel.ld ${EXTRACT_DIR}/*.o
     -melf_i386 -o ${CMAKE_BINARY_DIR}/kernel.out
 )
 
@@ -133,12 +130,16 @@ add_custom_target(mbr_hole.bin
 add_custom_target(boot.img
     DEPENDS mbr.bin
     DEPENDS mbr_hole.bin
+    DEPENDS user_space_programs
     COMMAND dd if=mbr.bin of=boot.img
     COMMAND cat mbr_hole.bin >> boot.img
     COMMAND dd if=/dev/zero of=boot.img bs=`expr 512 \\* 1024 \\* 1024` count=0 seek=1
     COMMAND sh -c \"echo n\; echo\; echo\; echo\; echo\; echo a\; echo w\" | fdisk boot.img
     COMMAND mkfs.fat --offset=2048 -v -n SYSTEM boot.img
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/user.sym ::user.sym
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/hello-world.out ::hello.out
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/interrupt-test.out ::int.out
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/stack-test.out ::stack.out
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/init.out ::init.elf
 )
 
 add_custom_command(OUTPUT run

+ 1 - 1
include/kernel/hw/ata.hpp

@@ -57,5 +57,5 @@ public:
     int write_sector(const char* buf, uint32_t lba_low, uint16_t lba_high) const;
 };
 
-void init_ata(void* data);
+void NORETURN init_ata(void* data);
 } // namespace hw

+ 4 - 2
include/kernel/process.hpp

@@ -44,7 +44,9 @@ public:
     process(process&& val);
     process(const process&) = delete;
     process(const process& proc, const thread& main_thread);
-    process(void* start_eip, uint8_t* image, size_t image_size, bool system);
+
+    // only used for system initialization
+    process(void* start_eip);
 };
 
 // in process.cpp
@@ -62,7 +64,7 @@ void process_context_load(interrupt_stack*, process* proc);
 void add_to_process_list(process&& proc);
 void add_to_ready_list(thread* thd);
 
-void k_new_thread(void(*func)(void*), void* data);
+void k_new_thread(void (*func)(void*), void* data);
 
 #else
 

+ 114 - 0
include/types/elf.hpp

@@ -0,0 +1,114 @@
+#pragma once
+#include <kernel/errno.h>
+#include <kernel/interrupt.h>
+#include <kernel/process.hpp>
+#include <kernel/vfs.hpp>
+#include <types/size.h>
+#include <types/status.h>
+#include <types/stdint.h>
+
+namespace types::elf {
+using elf32_addr_t = uint32_t;
+using elf32_off_t = uint32_t;
+
+using elf_addr_t = elf32_addr_t;
+using elf_off_t = elf32_off_t;
+
+constexpr elf32_addr_t ELF_STACK_BOTTOM = 0xfffff000;
+constexpr elf32_off_t ELF_STACK_SIZE = 8 * 1024 * 1024;
+constexpr elf32_addr_t ELF_STACK_TOP = ELF_STACK_BOTTOM - ELF_STACK_SIZE;
+
+struct PACKED elf32_header {
+    // 0x7f, "ELF"
+    char magic[4];
+
+    enum : uint8_t {
+        FORMAT_32 = 1,
+        FORMAT_64 = 2,
+    } format;
+    enum : uint8_t {
+        ENDIAN_LITTLE = 1,
+        ENDIAN_BIG = 2,
+    } endian;
+    // should be 1
+    uint8_t _version1;
+    enum : uint8_t {
+        ABI_SYSTEM_V = 0x00,
+        // TODO:
+        ABI_LINUX = 0x03,
+    } abi;
+    uint8_t abi_version;
+    uint8_t _reserved[7];
+    enum : uint16_t {
+        ET_NONE = 0x00,
+        ET_REL = 0x01,
+        ET_EXEC = 0x02,
+        ET_DYN = 0x03,
+        ET_CORE = 0x04,
+        ET_LOOS = 0xfe00,
+        ET_HIOS = 0xfeff,
+        ET_LOPROC = 0xff00,
+        ET_HIPROC = 0xffff,
+    } type;
+    enum : uint16_t {
+        ARCH_NONE = 0x00,
+        ARCH_X86 = 0x03,
+        ARCH_ARM = 0x28,
+        ARCH_IA64 = 0x32,
+        ARCH_X86_64 = 0x3e,
+        ARCH_ARM64 = 0xb7,
+        ARCH_RISCV = 0xf3,
+    } arch;
+    // should be 1
+    uint32_t _version2;
+    // entry address
+    elf32_addr_t entry;
+    // program header table offset
+    elf32_off_t phoff;
+    // section header table offset
+    elf32_off_t shoff;
+    // architecture dependent flags
+    uint32_t flags;
+    // elf header size
+    uint16_t ehsize;
+    // program header table entry size
+    uint16_t phentsize;
+    // program header table entries number
+    uint16_t phnum;
+    // section header table entry size
+    uint16_t shentsize;
+    // section header table entries number
+    uint16_t shnum;
+    // section header table entry index that contains section names
+    uint16_t shstrndx;
+};
+
+struct PACKED elf32_program_header_entry {
+    enum : uint32_t {
+        PT_NULL = 0x00,
+        PT_LOAD = 0x01,
+        PT_DYNAMIC = 0x02,
+        PT_INTERP = 0x03,
+        PT_NOTE = 0x04,
+        PT_SHLIB = 0x05,
+        PT_PHDR = 0x06,
+        PT_TLS = 0x07,
+        PT_LOOS = 0x60000000,
+        PT_HIOS = 0x6fffffff,
+        PT_LIPROC = 0x70000000,
+        PT_HIPROC = 0x7fffffff,
+    } type;
+    elf32_off_t offset;
+    elf32_addr_t vaddr;
+    elf32_addr_t paddr;
+    elf32_off_t filesz;
+    elf32_off_t memsz;
+    // segment dependent
+    uint32_t flags;
+    // 0 and 1 for no alignment, otherwise power of 2
+    uint32_t align;
+};
+
+int elf32_load(const char* exec, interrupt_stack* intrpt_stack, bool system);
+
+} // namespace types::elf

+ 0 - 22
src/asm/sys.s

@@ -52,25 +52,3 @@ asm_load_tr:
     orl $0, %eax
     ltr %ax
     ret
-
-.globl go_user_space
-.type  go_user_space @function
-go_user_space:
-    movl $((4 * 8) | 3), %eax
-    movw %ax, %ds
-    movw %ax, %es
-    movw %ax, %fs
-    movw %ax, %gs
-
-    movl 4(%esp), %ebx
-    pushl $((4 * 8) | 3)
-    pushl $0x40100000
-    pushf
-    # allow interrupts in user mode
-    movl (%esp), %eax
-    orl $0x200, %eax
-    movl %eax, (%esp)
-    pushl $((3 * 8) | 3)
-    pushl %ebx
-
-    iret

+ 8 - 2
src/kernel/hw/ata.cpp

@@ -196,9 +196,10 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
     }
 }
 
-void hw::init_ata(void* data)
+// data: void (*func_to_call_next)(void)
+void NORETURN hw::init_ata(void* data)
 {
-    if (data != nullptr)
+    if (!data)
         syscall(0x03);
 
     ata_pri = types::kernel_allocator_new<ata>(ATA_PRIMARY_BUS_BASE);
@@ -229,4 +230,9 @@ void hw::init_ata(void* data)
 
     auto* hda = fs::vfs_open("/dev/hda");
     mbr_part_probe(hda->ind, 2, 1);
+
+    // noreturn
+    ((void (*)(void))data)();
+    for (;;)
+        syscall(0x03);
 }

+ 67 - 54
src/kernel/process.cpp

@@ -1,17 +1,22 @@
 #include <asm/port_io.h>
 #include <asm/sys.h>
+#include <fs/fat.hpp>
+#include <kernel/hw/ata.hpp>
+#include <kernel/interrupt.h>
+#include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
 #include <kernel/stdio.h>
+#include <kernel/syscall.hpp>
 #include <kernel/tty.h>
-#include <kernel/hw/ata.hpp>
+#include <kernel/vfs.hpp>
 #include <kernel_main.h>
-#include <types/types.h>
+#include <types/allocator.hpp>
+#include <types/elf.hpp>
 #include <types/lock.h>
-#include <hello-world.res>
-#include <interrupt-test.res>
+#include <types/status.h>
+#include <types/types.h>
 
-extern "C" void NORETURN go_user_space(void* eip);
 extern "C" void NORETURN to_kernel(interrupt_stack* ret_stack);
 extern "C" void NORETURN to_user(interrupt_stack* ret_stack);
 
@@ -19,8 +24,8 @@ static bool is_scheduler_ready;
 static types::list<process>* processes;
 static types::list<thread*>* ready_thds;
 static pid_t max_pid = 1;
-static void (* volatile kthreadd_new_thd_func)(void*);
-static void  * volatile kthreadd_new_thd_data;
+static void (*volatile kthreadd_new_thd_func)(void*);
+static void* volatile kthreadd_new_thd_data;
 static uint32_t volatile kthreadd_lock = 0;
 
 thread* current_thread;
@@ -68,11 +73,11 @@ process::process(const process& val, const thread& main_thd)
             iter_dst->pd = pd;
             for (auto pg = iter_src->pgs->begin(); pg != iter_src->pgs->end(); ++pg)
                 k_map(iter_dst.ptr(),
-                        &*pg,
-                        iter_src->attr.read,
-                        iter_src->attr.write,
-                        iter_src->attr.system,
-                        1);
+                    &*pg,
+                    iter_src->attr.read,
+                    iter_src->attr.write,
+                    iter_src->attr.system,
+                    1);
         }
     } else {
         // TODO: allocate low mem
@@ -90,10 +95,10 @@ process::process(const process& val, const thread& main_thd)
     }
 }
 
-process::process(void* start_eip, uint8_t* image, size_t image_size, bool system)
+process::process(void* start_eip)
     : mms(*kernel_mms)
     , thds {}
-    , attr { .system = system }
+    , attr { .system = 1 }
     , pid { max_pid++ }
 {
     // TODO: allocate low mem
@@ -104,12 +109,11 @@ process::process(void* start_eip, uint8_t* image, size_t image_size, bool system
     auto thd = thds.emplace_back(thread {
         .eip = start_eip,
         .owner = this,
-        // TODO: change this
         .regs {
             .edi {},
             .esi {},
-            .ebp = system ? (uint32_t)k_esp : 0x40100000U,
-            .esp = system ? (uint32_t)k_esp : 0x40100000U,
+            .ebp = reinterpret_cast<uint32_t>(k_esp),
+            .esp = reinterpret_cast<uint32_t>(k_esp),
             .ebx {},
             .edx {},
             .ecx {},
@@ -117,46 +121,49 @@ process::process(void* start_eip, uint8_t* image, size_t image_size, bool system
         },
         .eflags {},
         .attr {
-            .system = system,
+            .system = 1,
             .ready = 1,
             .wait = 0,
         },
     });
     ready_thds->push_back(thd.ptr());
+}
 
-    if (!system) {
-        page_directory_entry* pd = alloc_pd();
-        memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
-        for (auto& item : mms)
-            item.pd = pd;
+void NORETURN _kernel_init(void)
+{
+    // TODO: parse kernel parameters
+    auto* _new_fs = fs::register_fs(types::kernel_allocator_new<fs::fat::fat32>(fs::vfs_open("/dev/hda1")->ind));
+    int ret = fs::fs_root->ind->fs->mount(fs::vfs_open("/mnt"), _new_fs);
+    if (ret != GB_OK)
+        syscall(0x03);
 
-        auto user_mm = mms.emplace_back(0x40000000U, pd, 1, system);
+    page_directory_entry* new_pd = alloc_pd();
+    memcpy(new_pd, mms_get_pd(kernel_mms), PAGE_SIZE);
 
-        // TODO: change this
-        for (int i = 0; i < 1 * 1024 * 1024 / PAGE_SIZE; ++i)
-            k_map(user_mm.ptr(), &empty_page, 1, 1, 0, 1);
+    asm_cli();
 
-        auto* old_pd = reinterpret_cast<page_directory_entry*>(p_ptr_to_v_ptr(current_pd()));
-        auto* old_proc = current_process;
-        auto* old_thd = current_thread;
+    current_process->mms.begin()->pd = new_pd;
 
-        current_process = this;
-        current_thread = thd.ptr();
-        asm_switch_pd(pd);
+    asm_sti();
 
-        // TODO: change this
-        memcpy((void*)0x40000000U, image, image_size);
+    interrupt_stack intrpt_stack {};
+    intrpt_stack.eflags = 0x200; // STI
+    types::elf::elf32_load("/mnt/INIT.ELF", &intrpt_stack, 0);
+    // map stack area
+    ret = mmap((void*)types::elf::ELF_STACK_TOP, types::elf::ELF_STACK_SIZE, fs::vfs_open("/dev/null")->ind, 0, 1, 0);
+    if (ret != GB_OK)
+        syscall(0x03);
 
-        current_process = old_proc;
-        current_thread = old_thd;
-        asm_switch_pd(old_pd);
-    }
+    asm_cli();
+    current_process->attr.system = 0;
+    current_thread->attr.system = 0;
+    to_user(&intrpt_stack);
 }
 
 void kernel_threadd_main(void)
 {
     tty_print(console, "kernel thread daemon started\n");
-    k_new_thread(hw::init_ata, nullptr);
+    k_new_thread(hw::init_ata, (void*)_kernel_init);
     for (;;) {
         if (kthreadd_new_thd_func) {
             spin_lock(&kthreadd_lock);
@@ -170,12 +177,16 @@ void kernel_threadd_main(void)
             spin_unlock(&kthreadd_lock);
 
             // syscall_fork
-            asm volatile("movl $0x00, %%eax\nint $0x80\nmovl %%eax, %0": "=a" (return_value): :);
+            asm volatile("movl $0x00, %%eax\nint $0x80\nmovl %%eax, %0"
+                         : "=a"(return_value)
+                         :
+                         :);
 
             if (return_value != 0) {
                 // child
                 func(data);
-                for (;;) asm_hlt();
+                for (;;)
+                    syscall(0x03);
                 // TODO: syscall_exit()
             }
             spin_unlock(&kthreadd_lock);
@@ -184,7 +195,7 @@ void kernel_threadd_main(void)
     }
 }
 
-void k_new_thread(void(*func)(void*), void* data)
+void k_new_thread(void (*func)(void*), void* data)
 {
     spin_lock(&kthreadd_lock);
     kthreadd_new_thd_func = func;
@@ -197,24 +208,26 @@ void NORETURN init_scheduler()
     processes = types::kernel_allocator_new<types::list<process>>();
     ready_thds = types::kernel_allocator_new<types::list<thread*>>();
 
-    void* user_space_start = reinterpret_cast<void*>(0x40000000U);
+    auto iter = processes->emplace_back((void*)kernel_threadd_main);
 
-    processes->emplace_back(user_space_start, hello_world_bin, hello_world_bin_len, false);
-    processes->emplace_back(user_space_start, interrupt_test_bin, interrupt_test_bin_len, false);
-    processes->emplace_back((void*)kernel_threadd_main, nullptr, 0, true);
-
-    // we need interrupts enabled for cow mapping
+    // we need interrupts enabled for cow mapping so now we disable it
+    // in case timer interrupt mess things up
     asm_cli();
 
-    auto init_process = processes->begin();
-    current_process = init_process.ptr();
-    current_thread = init_process->thds.begin().ptr();
+    current_process = iter.ptr();
+    current_thread = iter->thds.begin().ptr();
+
     tss.ss0 = KERNEL_DATA_SEGMENT;
-    tss.esp0 = (uint32_t)init_process->k_esp;
+    tss.esp0 = (uint32_t)iter->k_esp;
+
     asm_switch_pd(mms_get_pd(&current_process->mms));
 
     is_scheduler_ready = true;
-    go_user_space(user_space_start);
+
+    interrupt_stack intrpt_stack {};
+    process_context_load(&intrpt_stack, current_process);
+    thread_context_load(&intrpt_stack, current_thread);
+    to_kernel(&intrpt_stack);
 }
 
 void thread_context_save(interrupt_stack* int_stack, thread* thd)

+ 24 - 3
src/kernel/syscall.cpp

@@ -1,7 +1,9 @@
 #include <asm/port_io.h>
-#include <kernel/syscall.hpp>
+#include <kernel/interrupt.h>
 #include <kernel/process.hpp>
+#include <kernel/syscall.hpp>
 #include <kernel/tty.h>
+#include <types/elf.hpp>
 
 syscall_handler syscall_handlers[8];
 
@@ -56,14 +58,33 @@ void _syscall_crash(interrupt_stack*)
     asm_hlt();
 }
 
+// syscall_exec(const char* exec, const char** argv)
+// @param exec: the path of program to execute
+// @param argv: arguments end with nullptr
+void _syscall_exec(interrupt_stack* data)
+{
+    const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
+
+    // TODO: load argv
+    const char** argv = reinterpret_cast<const char**>(data->s_regs.esi);
+    (void)argv;
+
+    types::elf::elf32_load(exec, data, current_process->attr.system);
+}
+
+void _syscall_exit(interrupt_stack* data)
+{
+    _syscall_crash(data);
+}
+
 void init_syscall(void)
 {
     syscall_handlers[0] = _syscall_fork;
     syscall_handlers[1] = _syscall_write;
     syscall_handlers[2] = _syscall_sleep;
     syscall_handlers[3] = _syscall_crash;
-    syscall_handlers[4] = _syscall_not_impl;
-    syscall_handlers[5] = _syscall_not_impl;
+    syscall_handlers[4] = _syscall_exec;
+    syscall_handlers[5] = _syscall_exit;
     syscall_handlers[6] = _syscall_not_impl;
     syscall_handlers[7] = _syscall_not_impl;
 }

+ 1 - 0
src/kernel/vfs.cpp

@@ -466,6 +466,7 @@ void init_vfs(void)
 
     vfs_mkdir(fs_root, "dev");
     vfs_mkdir(fs_root, "root");
+    vfs_mkdir(fs_root, "mnt");
     vfs_mkfile(fs_root, "init");
 
     auto* init = vfs_open("/init");

+ 60 - 0
src/types/elf.cpp

@@ -0,0 +1,60 @@
+#include <types/elf.hpp>
+
+int types::elf::elf32_load(const char* exec, interrupt_stack* intrpt_stack, bool system)
+{
+    auto* ent_exec = fs::vfs_open(exec);
+    if (!ent_exec) {
+        intrpt_stack->s_regs.eax = ENOENT;
+        intrpt_stack->s_regs.edx = 0;
+        return GB_FAILED;
+    }
+
+    // TODO: detect file format
+    types::elf::elf32_header hdr {};
+    auto n_read = fs::vfs_read(
+        ent_exec->ind,
+        (char*)&hdr,
+        sizeof(types::elf::elf32_header),
+        0, sizeof(types::elf::elf32_header));
+
+    if (n_read != sizeof(types::elf::elf32_header)) {
+        intrpt_stack->s_regs.eax = EINVAL;
+        intrpt_stack->s_regs.edx = 0;
+        return GB_FAILED;
+    }
+
+    size_t phents_size = hdr.phentsize * hdr.phnum;
+    auto* phents = (types::elf::elf32_program_header_entry*)k_malloc(phents_size);
+    n_read = fs::vfs_read(
+        ent_exec->ind,
+        (char*)phents,
+        phents_size,
+        hdr.phoff, phents_size);
+
+    // broken file or I/O error
+    if (n_read != phents_size) {
+        intrpt_stack->s_regs.eax = EINVAL;
+        intrpt_stack->s_regs.edx = 0;
+        return GB_FAILED;
+    }
+
+    for (int i = 0; i < hdr.phnum; ++i) {
+        if (phents->type != types::elf::elf32_program_header_entry::PT_LOAD)
+            continue;
+
+        auto ret = mmap((void*)phents->vaddr, phents->memsz, ent_exec->ind, phents->offset, 1, system);
+        if (ret != GB_OK) {
+            intrpt_stack->s_regs.eax = ret;
+            intrpt_stack->s_regs.edx = 0;
+            return GB_FAILED;
+        }
+
+        ++phents;
+    }
+
+    intrpt_stack->v_eip = (void*)hdr.entry;
+    memset((void*)&intrpt_stack->s_regs, 0x00, sizeof(regs_32));
+    intrpt_stack->s_regs.esp = types::elf::ELF_STACK_BOTTOM;
+    intrpt_stack->s_regs.ebp = types::elf::ELF_STACK_BOTTOM;
+    return GB_OK;
+}

+ 20 - 13
user-space-program/Makefile.src

@@ -1,30 +1,37 @@
 CROSS_COMPILE=
 CC=$(CROSS_COMPILE)gcc
 LD=$(CROSS_COMPILE)ld
+OBJCOPY=$(CROSS_COMPILE)objcopy
 XXD=xxd
 
-RES=hello-world.res interrupt-test.res
-OBJS=hello-world.o interrupt-test.o
+CFLAGS=-nostdinc -nostdlib -static -g -m32 -W -Wall -Wextra -Werror
 
-all: user.sym $(RES)
+OBJS=hello-world.out interrupt-test.out stack-test.out init.out
+SYMS=init.sym
+
+all: $(OBJS) $(SYMS)
 	mkdir -p build
-	cp $(RES) build
+	mv $(OBJS) build
+	mv $(SYMS) build
 
-user.sym: $(OBJS) output_symbols.ld
-	$(LD) -r -T output_symbols.ld $(OBJS) -o user.sym
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
 
 %.o: %.s
-	$(CC) -c -g -m32 -o $@ $<
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.out1: %.o script.ld
+	$(LD) -nostdlib -e main -Ttext 0x40000000 -T script.ld $< -o $@
 
-%.bin: %.o output_code.ld
-	$(LD) -T output_code.ld $< -o $@
+%.out: %.out1
+	$(OBJCOPY) --strip-debug $< $@
 
-%.res: %.bin
-	$(XXD) -i $< $@
+%.sym: %.out1
+	$(OBJCOPY) --only-keep-debug $< $@
 
 .PHONY: clean
 clean:
 	-rm -rf build
 	-rm $(OBJS)
-	-rm $(RES)
-	-rm user.sym
+	-rm $(SYMS)
+	-rm compile_commands.json

+ 17 - 0
user-space-program/basic-lib.h

@@ -0,0 +1,17 @@
+typedef __UINT32_TYPE__ uint32_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT8_TYPE__ uint8_t;
+
+static inline uint32_t syscall(uint32_t num, uint32_t arg1, uint32_t arg2)
+{
+    asm ("movl %3, %%eax\n\
+          movl %1, %%edi\n\
+          movl %2, %%esi\n\
+          int $0x80\n\
+          movl %%eax, %0"
+         :"=r"(num)
+         :"0"(arg1), "r"(arg2), "r"(num)
+         :"eax", "edi", "esi"
+         );
+    return num;
+}

+ 9 - 0
user-space-program/configure

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+cp Makefile.src Makefile
+
+make --always-make --dry-run \
+    | grep -wE 'gcc|g\+\+' \
+    | grep -w '\-c' \
+    | jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$").string[1:]}]' \
+    > compile_commands.json

+ 4 - 3
user-space-program/hello-world.s

@@ -1,8 +1,9 @@
 .code32
-.section .text.user-space
 
-.globl user_hello_world
-user_hello_world:
+.text
+
+.globl main
+main:
 	movl $0xcbcbcbcb, %eax
 	movl $0xacacacac, %ebx
 	jmp .

+ 9 - 0
user-space-program/init.c

@@ -0,0 +1,9 @@
+#include "basic-lib.h"
+
+int main(void)
+{
+    const char* data = "Hello World from user space init\n";
+    syscall(0x01, (uint32_t)data, 0);
+    for (;;) ;
+    return 0;
+}

+ 7 - 4
user-space-program/interrupt-test.s

@@ -1,8 +1,9 @@
 .code32
-.section .text.user-space
 
-.globl user_interrupt_test
-user_interrupt_test:
+.text
+
+.globl main
+main:
 # fork 1 -> 2
 	xorl %eax, %eax
 	int $0x80
@@ -22,5 +23,7 @@ user_interrupt_test:
 # noreturn
 	jmp .
 
+.data
+
 __user_interrupt_test_string:
-	.ascii "syscall 0x01 write: hello from user space\n\0"
+	.asciz "syscall 0x01 write: hello from user space\n"

+ 0 - 20
user-space-program/output_code.ld

@@ -1,20 +0,0 @@
-OUTPUT_FORMAT(binary)
-OUTPUT_ARCH(i386:i386)
-
-SECTIONS
-{
-    .text 0x40000000 : AT(0x00)
-    {
-        *(.text*)
-        *(.rodata*)
-        *(.data)
-        *(.data*)
-        *(.bss)
-        *(.bss*)
-    }
-
-    /DISCARD/ :
-    {
-        *(.note.gnu.property)
-    }
-}

+ 0 - 47
user-space-program/output_symbols.ld

@@ -1,47 +0,0 @@
-OUTPUT_FORMAT(elf32-i386)
-OUTPUT_ARCH(i386:i386)
-
-SECTIONS
-{
-    /DISCARD/ :
-    {
-        *(.text*)
-        *(.data)
-        *(.data*)
-        *(.note.gnu.property)
-    }
-
-    /* Stabs debugging sections.  */
-    .stab          0 : { *(.stab) }
-    .stabstr       0 : { *(.stabstr) }
-    .stab.excl     0 : { *(.stab.excl) }
-    .stab.exclstr  0 : { *(.stab.exclstr) }
-    .stab.index    0 : { *(.stab.index) }
-    .stab.indexstr 0 : { *(.stab.indexstr) }
-    .comment       0 : { *(.comment) }
-    /* DWARF debug sections.
-       Symbols in the DWARF debugging sections are relative to the beginning
-       of the section so we begin them at 0.  */
-    /* DWARF 1 */
-    .debug          0 : { *(.debug) }
-    .line           0 : { *(.line) }
-    /* GNU DWARF 1 extensions */
-    .debug_srcinfo  0 : { *(.debug_srcinfo) }
-    .debug_sfnames  0 : { *(.debug_sfnames) }
-    /* DWARF 1.1 and DWARF 2 */
-    .debug_aranges  0 : { *(.debug_aranges) }
-    .debug_pubnames 0 : { *(.debug_pubnames) }
-    /* DWARF 2 */
-    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
-    .debug_abbrev   0 : { *(.debug_abbrev) }
-    .debug_line     0 : { *(.debug_line) }
-    .debug_frame    0 : { *(.debug_frame) }
-    .debug_str      0 : { *(.debug_str) }
-    .debug_loc      0 : { *(.debug_loc) }
-    .debug_macinfo  0 : { *(.debug_macinfo) }
-    /* SGI/MIPS DWARF 2 extensions */
-    .debug_weaknames 0 : { *(.debug_weaknames) }
-    .debug_funcnames 0 : { *(.debug_funcnames) }
-    .debug_typenames 0 : { *(.debug_typenames) }
-    .debug_varnames  0 : { *(.debug_varnames) }
-}

+ 22 - 0
user-space-program/script.ld

@@ -0,0 +1,22 @@
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386:i386)
+
+MEMORY
+{
+    MEM : org = 0x40000000, l = 3072M
+
+}
+
+SECTIONS
+{
+    .text :
+    {
+        *(.text)
+        *(.text*)
+    } > MEM
+
+    /DISCARD/ :
+    {
+        *(.note.gnu.property*)
+    }
+}

+ 16 - 0
user-space-program/stack-test.s

@@ -0,0 +1,16 @@
+.code32
+
+.text
+
+.globl main
+.type  main @function
+main:
+	pushl %ebp
+	movl %esp, %ebp
+
+	movl %esp, %eax
+
+	movl %ebp, %esp
+	popl %ebp
+
+	jmp .