refactor: elf parsing utility and exec related
authorMinep <lunaixsky@qq.com>
Mon, 10 Jul 2023 20:37:38 +0000 (21:37 +0100)
committerMinep <lunaixsky@qq.com>
Mon, 10 Jul 2023 20:41:49 +0000 (21:41 +0100)
refactor: ISA abstraction setup

26 files changed:
lunaix-os/includes/arch/abi.h [new file with mode: 0644]
lunaix-os/includes/arch/x86/i386_abi.h [new file with mode: 0644]
lunaix-os/includes/arch/x86/i386_asm.h [new file with mode: 0644]
lunaix-os/includes/lunaix/common.h
lunaix-os/includes/lunaix/elf.h
lunaix-os/includes/lunaix/exec.h [moved from lunaix-os/includes/lunaix/ld.h with 56% similarity]
lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/mm/page.h
lunaix-os/includes/lunaix/mm/valloc.h
lunaix-os/includes/lunaix/spike.h
lunaix-os/includes/lunaix/status.h
lunaix-os/kernel/asm/x86/interrupt.S
lunaix-os/kernel/asm/x86/prologue.S
lunaix-os/kernel/fs/path_walk.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/loader/elf.c
lunaix-os/kernel/loader/exec.c
lunaix-os/kernel/loader/ld.c [deleted file]
lunaix-os/kernel/mm/dmm.c
lunaix-os/kernel/mm/mmap.c
lunaix-os/kernel/mm/valloc.c
lunaix-os/kernel/proc0.c
lunaix-os/kernel/process/process.c
lunaix-os/kernel/process/signal.c
lunaix-os/usr/uinit.c [deleted file]
lunaix-os/usr/uwrap.S

diff --git a/lunaix-os/includes/arch/abi.h b/lunaix-os/includes/arch/abi.h
new file mode 100644 (file)
index 0000000..baf7ff6
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __LUNAIX_ABI_H
+#define __LUNAIX_ABI_H
+
+/* clang-format off */
+
+#if 0
+// templates, new arch should implements these templates
+#define store_retval(retval)
+#endif
+
+#ifdef __ARCH_IA32
+    #include "x86/i386_asm.h"
+    #ifndef __ASM__
+        #include "x86/i386_abi.h"
+    #endif
+#endif
+
+/* clang-format on */
+
+#endif /* __LUNAIX_ABI_H */
diff --git a/lunaix-os/includes/arch/x86/i386_abi.h b/lunaix-os/includes/arch/x86/i386_abi.h
new file mode 100644 (file)
index 0000000..22481c9
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __LUNAIX_I386ABI_H
+#define __LUNAIX_I386ABI_H
+
+#define store_retval(retval) __current->intr_ctx.registers.eax = (retval)
+
+#define store_retval_to(proc, retval) (proc)->intr_ctx.registers.eax = (retval)
+
+#define j_usr(sp, pc)                                                          \
+    asm volatile("movw %0, %%ax\n"                                             \
+                 "movw %%ax, %%es\n"                                           \
+                 "movw %%ax, %%ds\n"                                           \
+                 "movw %%ax, %%fs\n"                                           \
+                 "movw %%ax, %%gs\n"                                           \
+                 "pushl %0\n"                                                  \
+                 "pushl %1\n"                                                  \
+                 "pushl %2\n"                                                  \
+                 "pushl %3\n"                                                  \
+                 "retf" ::"i"(UDATA_SEG),                                      \
+                 "r"(sp),                                                      \
+                 "i"(UCODE_SEG),                                               \
+                 "r"(pc)                                                       \
+                 : "eax", "memory");
+
+#endif /* __LUNAIX_ABI_H */
diff --git a/lunaix-os/includes/arch/x86/i386_asm.h b/lunaix-os/includes/arch/x86/i386_asm.h
new file mode 100644 (file)
index 0000000..5fec5b3
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __LUNAIX_I386_ASM_H
+#define __LUNAIX_I386_ASM_H
+
+#define KCODE_SEG 0x08
+#define KDATA_SEG 0x10
+#define UCODE_SEG 0x1B
+#define UDATA_SEG 0x23
+#define TSS_SEG 0x28
+
+#endif /* __LUNAIX_I386_ASM_H */
index daa55af83023e921746a6fc788a96716e4421d7f..3ed90f8cd54a4c01856405da9f5487e317e87f64 100644 (file)
@@ -24,9 +24,6 @@
 
 #define KCODE_SEG 0x08
 #define KDATA_SEG 0x10
-#define UCODE_SEG 0x1B
-#define UDATA_SEG 0x23
-#define TSS_SEG 0x28
 
 #define USTACK_SIZE MEM_4MB
 #define USTACK_TOP 0x9ffffff0
index f61fa962c91159bc39c7c08824cafb12e3a6106d..cff442c2f806ceee73b793796f57aac26596cb9a 100644 (file)
@@ -13,6 +13,7 @@ typedef unsigned int elf32_wrd_t;
 #define ET_EXEC 2
 
 #define PT_LOAD 1
+#define PT_INTERP 3
 
 #define PF_X 0x1
 #define PF_W 0x2
@@ -63,15 +64,60 @@ struct elf32_phdr
     elf32_wrd_t p_align;
 };
 
+struct elf32
+{
+    void* elf_file;
+    struct elf32_ehdr eheader;
+    struct elf32_phdr* pheaders;
+};
+
+#define declare_elf32(elf, elf_vfile)                                          \
+    struct elf32 elf = { .elf_file = elf_vfile, .pheaders = (void*)0 }
+
+int
+elf32_open(struct elf32* elf, const char* path);
+
+int
+elf32_openat(struct elf32* elf, void* elf_vfile);
+
+int
+elf32_static_linked(const struct elf32* elf);
+
+int
+elf32_close(struct elf32* elf);
+
+/**
+ * @brief Try to find the PT_INTERP section. If found, copy it's content to
+ * path_out
+ *
+ * @param elf Opened elf32 descriptor
+ * @param path_out
+ * @param len size of path_out buffer
+ * @return int
+ */
+int
+elf32_find_loader(const struct elf32* elf, char* path_out, size_t len);
+
+int
+elf32_read_ehdr(struct elf32* elf);
+
+int
+elf32_read_phdr(struct elf32* elf);
+
+/**
+ * @brief Estimate how much memeory will be acquired if we load all loadable
+ * sections.、
+ *
+ * @param elf
+ * @return size_t
+ */
+size_t
+elf32_loadable_memsz(const struct elf32* elf);
+
+int
+elf32_load(struct load_context* ldctx, const struct elf32* elf);
+
 #define SIZE_EHDR sizeof(struct elf32_ehdr)
 #define SIZE_PHDR sizeof(struct elf32_phdr)
 
-static inline int
-elf_check_exec(struct elf32_ehdr* ehdr)
-{
-    return *(u32_t*)(ehdr->e_ident) == ELFMAGIC &&
-           ehdr->e_ident[EI_CLASS] == ELFCLASS32 &&
-           ehdr->e_ident[EI_DATA] == ELFDATA2LSB && ehdr->e_type == ET_EXEC &&
-           ehdr->e_machine == EM_386;
-}
 #endif /* __LUNAIX_ELF_H */
similarity index 56%
rename from lunaix-os/includes/lunaix/ld.h
rename to lunaix-os/includes/lunaix/exec.h
index 690f95fb616e87ad9100af753a341aca381a5e67..00f4d398b42fef007760b3257857e9e5a5fc4b6b 100644 (file)
@@ -1,62 +1,67 @@
-#ifndef __LUNAIX_LOADER_H
-#define __LUNAIX_LOADER_H
+#ifndef __LUNAIX_EXEC_H
+#define __LUNAIX_EXEC_H
 
 #include <lunaix/elf.h>
+#include <lunaix/fs.h>
 #include <lunaix/process.h>
 #include <lunaix/types.h>
 
-#define LD_STAT_FKUP 0x1U
+#define NO_LOADER 0
+#define DEFAULT_LOADER "usr/ld"
 
 #define MAX_VAR_PAGES 8
 #define DEFAULT_HEAP_PAGES 16
 
-struct ld_info
+struct exec_context;
+
+struct load_context
 {
-    struct elf32_ehdr ehdr_out;
+    struct exec_container* container;
     ptr_t base;
     ptr_t end;
     ptr_t mem_sz;
 
-    ptr_t stack_top;
     ptr_t entry;
 };
 
-struct ld_param
+struct exec_container
 {
     struct proc_info* proc;
     ptr_t vms_mnt;
 
-    struct ld_info info;
+    struct load_context executable;
+
+    ptr_t stack_top;
+    ptr_t entry; // mapped to one of {executable|loader}.entry
+
     int status;
 };
 
-struct usr_exec_param
+struct uexec_param
 {
     int argc;
     char** argv;
     int envc;
     char** envp;
-    struct ld_info info;
 } PACKED;
 
 #ifndef __USR_WRAPPER__
-int
-elf_load(struct ld_param* ldparam, struct v_file* elfile);
 
 int
-exec_load_byname(struct ld_param* param,
+exec_load_byname(struct exec_container* container,
                  const char* filename,
                  const char** argv,
                  const char** envp);
 
 int
-exec_load(struct ld_param* param,
+exec_load(struct exec_container* container,
           struct v_file* executable,
           const char** argv,
           const char** envp);
 
-void
-ld_create_param(struct ld_param* param, struct proc_info* proc, ptr_t vms);
+int
+exec_kexecve(const char* filename, const char* argv[], const char* envp);
+
 #endif
 
 #endif /* __LUNAIX_LOADER_H */
index add77983b5fd1008857374f6b767152d2593dbb1..5fbcc9083791607d8448cdaa53c7d1019cd90385 100644 (file)
 #define VFS_IFVOLDEV 0x8
 #define VFS_IFSYMLINK 0x10
 
+// Walk, mkdir if component encountered is non-exists.
 #define VFS_WALK_MKPARENT 0x1
+
+// Walk, relative to current FS.
 #define VFS_WALK_FSRELATIVE 0x2
+
+/*
+    Terminate the walk on the immediate parent,
+    name of child (last component) is returned through `component`
+*/
 #define VFS_WALK_PARENT 0x4
+
+// Do not follow the symbolic link
 #define VFS_WALK_NOFOLLOW 0x8
 
 #define VFS_HASHTABLE_BITS 10
index 8720e1c917a0626a2f64cf13746415ce0c499c26..959477f50ac29561c524446f02978e4ee9dc214a 100644 (file)
@@ -107,6 +107,9 @@ extern void __pg_mount_point;
 #define PG_MOUNT_3 (PG_MOUNT_BASE + 0x2000)
 #define PG_MOUNT_4 (PG_MOUNT_BASE + 0x3000)
 
+/*
+    当前进程内存空间挂载点
+*/
 #define VMS_SELF L2_BASE_VADDR
 
 #define CURPROC_PTE(vpn)                                                       \
index 9be750c4e023a8e039d76256b9e6acefcdc91731..46428445a3cb5e2325bd88ce5297be4beba6b1ca 100644 (file)
@@ -13,6 +13,9 @@ vcalloc(unsigned int size, unsigned int count);
 void
 vfree(void* ptr);
 
+void
+vfree_safe(void* ptr);
+
 void*
 valloc_dma(unsigned int size);
 
index 6cece75784b807cd6c5e32a60d11a948edac5e54..5ea8d47b2b759068d41895ad1a622c7d9ce2fee7 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __LUNAIX_SPIKE_H
 #define __LUNAIX_SPIKE_H
 
-// Some helper functions. As helpful as Spike the Dragon! :)
+/** Some helper functions. As helpful as Spike the Dragon! :) **/
 
 // 除法 v/(2^k) 向上取整
 #define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k))
@@ -20,6 +20,8 @@
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
+#define likely(x) __builtin_expect((x), 1)
+
 /**
  * @brief Fast log base 2 for integer, utilizing constant unfolding.
  * Adopted from
@@ -91,7 +93,7 @@ __assert_fail(const char* expr, const char* file, unsigned int line)
 #define assert(cond) (void)(cond);          // assert nothing
 #define assert_msg(cond, msg) (void)(cond); // assert nothing
 
-#endif // __LUNAIXOS_NASSERT__
+#endif                                      // __LUNAIXOS_NASSERT__
 
 void
 panick(const char* msg);
index 31d2327f1f01bac60f867e66fdb86d8d62d1c00f..ffaacf51ce091b959e3462636f120f6c2233a08e 100644 (file)
@@ -32,5 +32,6 @@
 #define ENOTBLK -26
 #define ENOEXEC -27
 #define E2BIG -28
+#define ELIBBAD -29
 
 #endif /* __LUNAIX_CODE_H */
index 23df5b507a3a0b7c213d1a0407930a0b6c09d23d..a6c0496f651b90a0574364f619dfffb22ca23d7f 100644 (file)
@@ -1,6 +1,6 @@
 #define __ASM__
 #include <arch/x86/interrupts.h>
-#include <lunaix/common.h>
+#include <arch/x86/i386_asm.h>
 #include <lunaix/syscall.h>
 #define __ASM_INTR_DIAGNOSIS
 
index 6cdab40490e2c0e08a524412ca6021d1f6f4d812..4c183fb16150c57073e1b6fe83ea44f3978c2ff9 100644 (file)
@@ -1,7 +1,7 @@
 /* 高半核入口点 - 0xC0000000 */
 
 #define __ASM__
-#include <lunaix/common.h>
+#include <arch/x86/i386_asm.h>
 
 .section .text
     .global hhk_entry_
index f3dc8dd1bae87941bc926b095c7c817eaf26c569..07edfc70675065cf5959fb0d36123ddf3f700446 100644 (file)
@@ -148,8 +148,6 @@ __vfs_walk(struct v_dnode* start,
                 goto error;
             }
 
-            // reposition the resolved subtree pointed by symlink
-            // vfs_dcache_rehash(current_level->parent, dnode);
             current_level = dnode;
             current_inode = dnode->inode;
         }
index 7959fc3ffc3cce0cc58d79ec40ec777666480e5f..6f4b3b09532bee8d9ca3dbdb98faade21aedeb40 100644 (file)
@@ -1054,8 +1054,6 @@ __vfs_do_unlink(struct v_dnode* dnode)
     if (inode->open_count) {
         errno = EBUSY;
     } else if (!(inode->itype & VFS_IFDIR)) {
-        // The underlying unlink implementation should handle
-        //  symlink case
         errno = inode->ops->unlink(inode);
         if (!errno) {
             vfs_d_free(dnode);
@@ -1108,10 +1106,8 @@ __DEFINE_LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
     errno = __vfs_try_locate_file(oldpath, &dentry, &to_link, 0);
     if (!errno) {
         errno = __vfs_try_locate_file(
-          newpath, &name_dentry, &name_file, FLOCATE_CREATE_EMPTY);
+          newpath, &name_dentry, &name_file, FLOCATE_CREATE_ONLY);
         if (!errno) {
-            errno = EEXIST;
-        } else if (name_file) {
             errno = vfs_link(to_link, name_file);
         }
     }
index f6d494759591a2c6e42c124ff387e405e1cbc9a8..fa6b57676dcd8466d14b02e1be87efde441a8cfc 100644 (file)
+#include <klibc/string.h>
 #include <lunaix/common.h>
 #include <lunaix/elf.h>
+#include <lunaix/exec.h>
 #include <lunaix/fs.h>
-#include <lunaix/ld.h>
 #include <lunaix/mm/mmap.h>
 #include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
 
+static inline int
+elf32_read(struct v_file* elf, void* data, size_t off, size_t len)
+{
+    // it is wise to do cached read
+    return pcache_read(elf->inode, data, len, off);
+}
+
 int
-elf_map_segment(struct ld_param* ldparam,
-                struct v_file* elfile,
-                struct elf32_phdr* phdr)
+elf32_map_segment(struct load_context* ldctx,
+                  const struct elf32* elf,
+                  struct elf32_phdr* phdre)
 {
-    assert(PG_ALIGNED(phdr->p_offset));
+    struct v_file* elfile = (struct v_file*)elf->elf_file;
+
+    assert(PG_ALIGNED(phdre->p_offset));
 
     int proct = 0;
-    if ((phdr->p_flags & PF_R)) {
+    if ((phdre->p_flags & PF_R)) {
         proct |= PROT_READ;
     }
-    if ((phdr->p_flags & PF_W)) {
+    if ((phdre->p_flags & PF_W)) {
         proct |= PROT_WRITE;
     }
-    if ((phdr->p_flags & PF_X)) {
+    if ((phdre->p_flags & PF_X)) {
         proct |= PROT_EXEC;
     }
 
-    struct mmap_param param = { .vms_mnt = ldparam->vms_mnt,
-                                .pvms = &ldparam->proc->mm,
+    struct exec_container* container = ldctx->container;
+    struct mmap_param param = { .vms_mnt = container->vms_mnt,
+                                .pvms = &container->proc->mm,
                                 .proct = proct,
-                                .offset = PG_ALIGN(phdr->p_offset),
-                                .mlen = ROUNDUP(phdr->p_memsz, PG_SIZE),
-                                .flen = phdr->p_filesz + PG_MOD(phdr->p_va),
+                                .offset = PG_ALIGN(phdre->p_offset),
+                                .mlen = ROUNDUP(phdre->p_memsz, PG_SIZE),
+                                .flen = phdre->p_filesz + PG_MOD(phdre->p_va),
                                 .flags = MAP_FIXED | MAP_PRIVATE,
                                 .type = REGION_TYPE_CODE };
 
     struct mm_region* seg_reg;
-    int status = mem_map(NULL, &seg_reg, PG_ALIGN(phdr->p_va), elfile, &param);
+    int status = mem_map(NULL, &seg_reg, PG_ALIGN(phdre->p_va), elfile, &param);
 
     if (!status) {
-        size_t next_addr = phdr->p_memsz + phdr->p_va;
-        ldparam->info.end = MAX(ldparam->info.end, ROUNDUP(next_addr, PG_SIZE));
-        ldparam->info.mem_sz += phdr->p_memsz;
+        size_t next_addr = phdre->p_memsz + phdre->p_va;
+        ldctx->end = MAX(ldctx->end, ROUNDUP(next_addr, PG_SIZE));
+        ldctx->mem_sz += phdre->p_memsz;
+    } else {
+        // we probably fucked up our process
+        terminate_proc(-1);
     }
 
     return status;
 }
 
 int
-elf_setup_mapping(struct ld_param* ldparam,
-                  struct v_file* elfile,
-                  struct elf32_ehdr* ehdr)
+elf32_open(struct elf32* elf, const char* path)
+{
+    struct v_dnode* elfdn;
+    struct v_inode* elfin;
+    struct v_file* elffile;
+    int error = 0;
+
+    if ((error = vfs_walk_proc(path, &elfdn, NULL, 0))) {
+        return error;
+    }
+
+    if ((error = vfs_open(elfdn, &elffile))) {
+        return error;
+    }
+
+    return elf32_openat(elf, elffile);
+}
+
+int
+elf32_openat(struct elf32* elf, void* elf_vfile)
 {
     int status = 0;
-    size_t tbl_sz = ehdr->e_phnum * SIZE_PHDR;
-    struct elf32_phdr* phdrs = valloc(tbl_sz);
+    elf->pheaders = NULL;
+    elf->elf_file = elf_vfile;
 
-    if (!phdrs) {
-        status = ENOMEM;
-        goto done;
+    if ((status = elf32_read_ehdr(elf)) < 0) {
+        elf32_close(elf);
+        return status;
     }
 
-    tbl_sz = 1 << ILOG2(tbl_sz);
-    status = elfile->ops->read(elfile->inode, phdrs, tbl_sz, ehdr->e_phoff);
+    if ((status = elf32_read_phdr(elf)) < 0) {
+        elf32_close(elf);
+        return status;
+    }
 
-    if (status < 0) {
-        goto done;
+    return status;
+}
+
+int
+elf32_close(struct elf32* elf)
+{
+    if (elf->pheaders) {
+        vfree(elf->pheaders);
     }
 
-    if (PG_ALIGN(phdrs[0].p_va) != USER_START) {
-        status = ENOEXEC;
-        goto done;
+    if (elf->elf_file) {
+        vfs_close((struct v_file*)elf->elf_file);
     }
 
-    size_t entries = tbl_sz / SIZE_PHDR;
-    for (size_t i = 0; i < entries; i++) {
-        struct elf32_phdr* phdr = &phdrs[i];
+    memset(elf, 0, sizeof(*elf));
+}
 
-        if (phdr->p_type == PT_LOAD) {
-            if (phdr->p_align == PG_SIZE) {
-                status = elf_map_segment(ldparam, elfile, phdr);
-            } else {
-                // surprising alignment!
-                status = ENOEXEC;
-            }
+int
+elf32_static_linked(const struct elf32* elf)
+{
+    for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
+        struct elf32_phdr* phdre = &elf->pheaders[i];
+        if (phdre->p_type == PT_INTERP) {
+            return 0;
         }
-        // TODO process other types of segments
+    }
+    return 1;
+}
 
-        if (status) {
-            // errno in the middle of mapping restructuring, it is impossible
-            // to recover!
-            ldparam->status |= LD_STAT_FKUP;
-            goto done;
+size_t
+elf32_loadable_memsz(const struct elf32* elf)
+{
+    // XXX: Hmmmm, I am not sure if we need this. This is designed to be handy
+    // if we decided to map the heap region before transfer to loader. As
+    // currently, we push *everything* to user-space loader, thus we modify the
+    // brk syscall to do the initial heap mapping.
+
+    size_t sz = 0;
+    for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
+        struct elf32_phdr* phdre = &elf->pheaders[i];
+        if (phdre->p_type == PT_LOAD) {
+            sz += phdre->p_memsz;
         }
     }
 
-done:
-    vfree(phdrs);
-    return status;
+    return sz;
 }
 
 int
-elf_load(struct ld_param* ldparam, struct v_file* elfile)
+elf32_find_loader(const struct elf32* elf, char* path_out, size_t len)
 {
-    struct elf32_ehdr* ehdr = valloc(SIZE_EHDR);
-    int status = elfile->ops->read(elfile->inode, ehdr, SIZE_EHDR, 0);
+    int retval = NO_LOADER;
+
+    assert_msg(len >= sizeof(DEFAULT_LOADER), "path_out: too small");
+
+    struct v_file* elfile = (struct v_file*)elf->elf_file;
+
+    for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
+        struct elf32_phdr* phdre = &elf->pheaders[i];
+        if (phdre->p_type == PT_INTERP) {
+            assert_msg(len >= phdre->p_filesz, "path_out: too small");
+            retval =
+              elf_read(elfile, path_out, phdre->p_offset, phdre->p_filesz);
+
+            if (retval < 0) {
+                return retval;
+            }
+
+            break;
+        }
+    }
+
+    return retval;
+}
+
+int
+elf32_read_ehdr(struct elf32* elf)
+{
+    struct v_file* elfile = (struct v_file*)elf->elf_file;
+    int status = elf_read(elfile, (void*)&elf->eheader, 0, SIZE_EHDR);
 
     if (status < 0) {
-        goto done;
+        return status;
     }
+}
 
-    if (!elf_check_exec(ehdr)) {
-        status = ENOEXEC;
-        goto done;
+int
+elf32_read_phdr(struct elf32* elf)
+{
+    int status = 0;
+
+    struct v_file* elfile = (struct v_file*)elf->elf_file;
+
+    size_t entries = elf->eheader.e_phnum;
+    size_t tbl_sz = entries * SIZE_PHDR;
+
+    struct elf32_phdr* phdrs = valloc(tbl_sz);
+
+    if (!phdrs) {
+        return ENOMEM;
     }
 
-    if ((status = elf_setup_mapping(ldparam, elfile, ehdr))) {
-        goto done;
+    status = elf_read(elfile, phdrs, elf->eheader.e_phoff, tbl_sz);
+
+    if (status < 0) {
+        vfree(phdrs);
+        return status;
     }
 
-    ldparam->info.ehdr_out = *ehdr;
+    elf->pheaders = phdrs;
+    return entries;
+}
+
+int
+elf32_check_exec(const struct elf32* elf)
+{
+    struct elf32_ehdr* ehdr = elf->pheaders;
+
+    return *(u32_t*)(ehdr->e_ident) == ELFMAGIC &&
+           ehdr->e_ident[EI_CLASS] == ELFCLASS32 &&
+           ehdr->e_ident[EI_DATA] == ELFDATA2LSB && ehdr->e_type == ET_EXEC &&
+           ehdr->e_machine == EM_386;
+}
+
+int
+elf32_load(struct load_context* ldctx, const struct elf32* elf)
+{
+    int err = 0;
+
+    struct v_file* elfile = (struct v_file*)elf->elf_file;
+
+    for (size_t i = 0; i < elf->eheader.e_phnum && !err; i++) {
+        struct elf32_phdr* phdr = &elf->pheaders[i];
+
+        if (phdr->p_type == PT_LOAD) {
+            if (phdr->p_align != PG_SIZE) {
+                // surprising alignment!
+                err = ENOEXEC;
+                continue;
+            }
+
+            err = elf_map_segment(ldctx, elf, phdr);
+        }
+        // TODO Handle relocation
+    }
 
 done:
-    vfree(ehdr);
-    return status;
+    return err;
 }
\ No newline at end of file
index 6a18ffca11d91bdbeec592bd7b84689266473f11..5024a1d8a1d8bb4368fed28aeecf94c6a54fa675 100644 (file)
@@ -1,7 +1,9 @@
+#include <arch/abi.h>
 #include <lunaix/elf.h>
+#include <lunaix/exec.h>
 #include <lunaix/fs.h>
-#include <lunaix/ld.h>
 #include <lunaix/mm/mmap.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/process.h>
 #include <lunaix/spike.h>
 
 #include <klibc/string.h>
 
+void
+exec_container(struct exec_container* param, struct proc_info* proc, ptr_t vms)
+{
+    *param = (struct exec_container){ .proc = proc,
+                                      .vms_mnt = vms,
+                                      .executable = { .container = param } };
+}
+
 size_t
 exec_str_size(const char** str_arr, size_t* length)
 {
@@ -33,63 +43,82 @@ exec_str_size(const char** str_arr, size_t* length)
     return sz + sizeof(char*);
 }
 
-void
-__heap_copied(struct mm_region* region)
-{
-    mm_index((void**)&region->proc_vms->heap, region);
-}
-
-int
-__exec_remap_heap(struct ld_param* param, struct proc_mm* pvms)
-{
-    if (pvms->heap) {
-        mem_unmap_region(param->vms_mnt, pvms->heap);
-    }
-
-    struct mmap_param map_param = { .pvms = pvms,
-                                    .vms_mnt = param->vms_mnt,
-                                    .flags = MAP_ANON | MAP_PRIVATE,
-                                    .type = REGION_TYPE_HEAP,
-                                    .proct = PROT_READ | PROT_WRITE,
-                                    .mlen = PG_SIZE };
-    int status = 0;
-    struct mm_region* heap;
-    if ((status = mem_map(NULL, &heap, param->info.end, NULL, &map_param))) {
-        param->status |= LD_STAT_FKUP;
-        return status;
-    }
-
-    heap->region_copied = __heap_copied;
-    mm_index((void**)&pvms->heap, heap);
-
-    return status;
-}
+// externed from mm/dmm.c
+extern int
+create_heap(struct proc_mm* pvms, ptr_t addr);
 
 int
-exec_load(struct ld_param* param,
+exec_load(struct exec_container* container,
           struct v_file* executable,
           const char** argv,
           const char** envp)
 {
     int errno = 0;
+    char* ldpath = NULL;
 
     size_t argv_len, envp_len;
     size_t sz_argv = exec_str_size(argv, &argv_len);
     size_t sz_envp = exec_str_size(envp, &envp_len);
-    size_t total_sz = ROUNDUP(sz_argv + sz_envp, PG_SIZE);
+    size_t var_sz = ROUNDUP(sz_envp, PG_SIZE);
 
-    if (total_sz / PG_SIZE > MAX_VAR_PAGES) {
+    char* argv_extra[2] = { executable->dnode->name.value, 0 };
+
+    if (var_sz / PG_SIZE > MAX_VAR_PAGES) {
         errno = E2BIG;
         goto done;
     }
 
-    if ((errno = elf_load(param, executable))) {
+    struct elf32 elf;
+
+    if ((errno = elf32_openat(&elf, executable))) {
+        goto done;
+    }
+
+    if (!elf32_check_exec(&elf)) {
+        errno = ENOEXEC;
+        goto done;
+    }
+
+    ldpath = valloc(512);
+    errno = elf32_find_loader(&elf, ldpath, 512);
+
+    if (errno < 0) {
+        vfree(ldpath);
         goto done;
     }
 
-    struct proc_mm* pvms = &param->proc->mm;
+    if (errno != NO_LOADER) {
+        // TODO load loader
+        argv_extra[1] = ldpath;
+
+        // close old elf
+        if ((errno = elf32_close(&elf))) {
+            goto done;
+        }
+
+        // open the loader instead
+        if ((errno = elf32_open(&elf, ldpath))) {
+            goto done;
+        }
+
+        // Is this the valid loader?
+        if (!elf32_static_linked(&elf) || !elf32_check_exec(&elf)) {
+            errno = ELIBBAD;
+            goto done_close_elf32;
+        }
+
+        // TODO: relocate loader
+    }
+
+    if ((errno = elf32_load(&container->executable, &elf))) {
+        goto done_close_elf32;
+    }
+
+    struct proc_mm* pvms = &container->proc->mm;
+
+    // A dedicated place for process variables (e.g. envp)
     struct mmap_param map_vars = { .pvms = pvms,
-                                   .vms_mnt = param->vms_mnt,
+                                   .vms_mnt = container->vms_mnt,
                                    .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED,
                                    .type = REGION_TYPE_VARS,
                                    .proct = PROT_READ,
@@ -97,49 +126,79 @@ exec_load(struct ld_param* param,
 
     void* mapped;
 
-    if ((errno = __exec_remap_heap(param, pvms))) {
-        goto done;
+    if (pvms->heap) {
+        mem_unmap_region(container->vms_mnt, pvms->heap);
+        pvms->heap = NULL;
+    }
+
+    if (!argv_extra[1]) {
+        // If loading a statically linked file, then heap remapping we can do,
+        // otherwise delayed.
+        create_heap(container->vms_mnt, PG_ALIGN(container->executable.end));
     }
 
     if ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_vars))) {
-        goto done;
+        goto done_close_elf32;
     }
 
-    if (param->vms_mnt == VMS_SELF) {
+    if (container->vms_mnt == VMS_SELF) {
         // we are loading executable into current addr space
 
         // make some handy infos available to user space
-        ptr_t arg_start = mapped + sizeof(struct usr_exec_param);
-        if (argv)
-            memcpy(arg_start, (void*)argv, sz_argv);
         if (envp)
-            memcpy(arg_start + sz_argv, (void*)envp, sz_envp);
+            memcpy(mapped, (void*)envp, sz_envp);
 
-        ptr_t* ustack = (ptr_t*)USTACK_TOP;
-        struct usr_exec_param* exec_param = (struct usr_exec_param*)mapped;
+        void* ustack = (void*)USTACK_TOP;
 
-        ustack[-1] = (ptr_t)mapped;
-        param->info.stack_top = &ustack[-1];
+        if (argv) {
+            ustack = (void*)((ptr_t)ustack - sz_argv);
+            memcpy(ustack, (void*)argv, sz_argv);
+        }
+
+        for (size_t i = 0; i < 2 && argv_extra[i]; i++, argv_len++) {
+            char* extra_arg = argv_extra[i];
+            size_t str_len = strlen(extra_arg);
+
+            ustack = (void*)((ptr_t)ustack - str_len);
+            memcpy(ustack, (void*)extra_arg, str_len);
+        }
+
+        // four args (arg{c|v}, env{c|p}) for main
+        struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
+
+        container->stack_top = (ptr_t)exec_param;
+
+        *exec_param = (struct uexec_param){
+            .argc = argv_len, .argv = ustack, .envc = envp_len, .envp = mapped
+        };
 
-        *exec_param = (struct usr_exec_param){ .argc = argv_len,
-                                               .argv = arg_start,
-                                               .envc = envp_len,
-                                               .envp = arg_start + sz_argv,
-                                               .info = param->info };
     } else {
-        // TODO need to find a way to inject argv and envp remotely
-        //      this is for the support of kernel level implementation of
-        //      posix_spawn
+        /*
+            TODO need to find a way to inject argv and envp remotely
+                 this is for the support of kernel level implementation of
+                 posix_spawn
+
+            IDEA
+                1. Allocate a orphaned physical page (i.e., do not belong to any
+                VMA)
+                2. Mounted to a temporary mount point in current VMA, (i.e.,
+                PG_MOUNT_*)
+                3. Do setup there.
+                4. Unmount then mounted to the foreign VMA as the first stack
+                page.
+        */
         fail("not implemented");
     }
 
-    param->info.entry = param->info.ehdr_out.e_entry;
+done_close_elf32:
+    elf32_close(&elf);
 done:
+    vfree_safe(ldpath);
     return errno;
 }
 
 int
-exec_load_byname(struct ld_param* param,
+exec_load_byname(struct exec_container* container,
                  const char* filename,
                  const char** argv,
                  const char** envp)
@@ -156,14 +215,28 @@ exec_load_byname(struct ld_param* param,
         goto done;
     }
 
-    if ((errno = exec_load(param, file, argv, envp))) {
-        vfs_pclose(file, __current->pid);
-    }
+    errno = exec_load(container, file, argv, envp);
 
 done:
     return errno;
 }
 
+int
+exec_kexecve(const char* filename, const char* argv[], const char* envp)
+{
+    int errno = 0;
+    struct exec_container container;
+    exec_container(&container, __current, VMS_SELF);
+
+    errno = exec_load_byname(&container, filename, argv, envp);
+
+    if (errno) {
+        return errno;
+    }
+
+    j_usr(container.stack_top, container.entry);
+}
+
 __DEFINE_LXSYSCALL3(int,
                     execve,
                     const char*,
@@ -174,26 +247,26 @@ __DEFINE_LXSYSCALL3(int,
                     envp[])
 {
     int errno = 0;
-    struct ld_param ldparam;
-    ld_create_param(&ldparam, __current, VMS_SELF);
-
-    if ((errno = exec_load_byname(&ldparam, filename, argv, envp))) {
-        if ((ldparam.status & LD_STAT_FKUP)) {
-            // we fucked up our address space.
-            terminate_proc(11451);
-            schedule();
-            fail("should not reach");
-        }
+    struct exec_container container;
+    exec_container(&container, __current, VMS_SELF);
+
+    if (!(errno = exec_load_byname(&container, filename, argv, envp))) {
         goto done;
     }
 
-    volatile struct exec_param* execp = __current->intr_ctx.execp;
-    execp->esp = ldparam.info.stack_top;
-    execp->eip = ldparam.info.entry;
-
     // we will jump to new entry point (_u_start) upon syscall's
     // return so execve 'will not return' from the perspective of it's invoker
+    volatile struct exec_param* execp = __current->intr_ctx.execp;
+    execp->esp = container.stack_top;
+    execp->eip = container.entry;
 
 done:
-    return DO_STATUS(errno);
+    // set return value
+    store_retval(DO_STATUS(errno));
+
+    // Always yield the process that want execve!
+    schedule();
+
+    // this will never get executed!
+    return -1;
 }
\ No newline at end of file
diff --git a/lunaix-os/kernel/loader/ld.c b/lunaix-os/kernel/loader/ld.c
deleted file mode 100644 (file)
index 413e0f8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <lunaix/ld.h>
-
-void
-ld_create_param(struct ld_param* param, struct proc_info* proc, ptr_t vms)
-{
-    *param = (struct ld_param){ .proc = proc, .vms_mnt = vms };
-}
\ No newline at end of file
index cc75bd9be9b4d5f32b782b28733fbf7be54fbd31..3da8501f34aecdb43aa89a1fcd3270d15e9e6b6a 100644 (file)
@@ -1,4 +1,5 @@
 #include <lunaix/mm/mmap.h>
+#include <lunaix/mm/vmm.h>
 #include <lunaix/process.h>
 #include <lunaix/status.h>
 
@@ -6,6 +7,31 @@
 #include <lunaix/syscall.h>
 #include <lunaix/syscall_utils.h>
 
+void
+__heap_copied(struct mm_region* region)
+{
+    mm_index((void**)&region->proc_vms->heap, region);
+}
+
+int
+create_heap(struct proc_mm* pvms, ptr_t addr)
+{
+    struct mmap_param map_param = { .pvms = pvms,
+                                    .vms_mnt = VMS_SELF,
+                                    .flags = MAP_ANON | MAP_PRIVATE,
+                                    .type = REGION_TYPE_HEAP,
+                                    .proct = PROT_READ | PROT_WRITE,
+                                    .mlen = PG_SIZE };
+    int status = 0;
+    struct mm_region* heap;
+    if ((status = mem_map(NULL, &heap, addr, NULL, &map_param))) {
+        return status;
+    }
+
+    heap->region_copied = __heap_copied;
+    mm_index((void**)&pvms->heap, heap);
+}
+
 __DEFINE_LXSYSCALL1(void*, sbrk, ssize_t, incr)
 {
     struct proc_mm* pvms = &__current->mm;
@@ -24,6 +50,10 @@ __DEFINE_LXSYSCALL1(int, brk, void*, addr)
     struct proc_mm* pvms = &__current->mm;
     struct mm_region* heap = pvms->heap;
 
+    if (!heap) {
+        return DO_STATUS(create_heap(pvms, addr));
+    }
+
     assert(heap);
     int err = mem_adjust_inplace(&pvms->regions, heap, (ptr_t)addr);
     return DO_STATUS(err);
index 383d83e9bad557fd60d8e8af687a008ee1c968e3..8eb7482b60af4b3bf7686a8e478ae0f54f1c7f52 100644 (file)
@@ -303,20 +303,19 @@ __DEFINE_LXSYSCALL3(void*, sys_mmap, void*, addr, size_t, length, va_list, lst)
         }
     }
 
-    struct v_fd* vfd;
-    if ((errno = vfs_getfd(fd, &vfd))) {
-        goto done;
-    }
-
-    struct v_file* file = vfd->file;
+    struct v_file* file = NULL;
 
     if (!(options & MAP_ANON)) {
+        struct v_fd* vfd;
+        if ((errno = vfs_getfd(fd, &vfd))) {
+            goto done;
+        }
+
+        file = vfd->file;
         if (!file->ops->read_page) {
             errno = ENODEV;
             goto done;
         }
-    } else {
-        file = NULL;
     }
 
     struct mmap_param param = { .flags = options,
index a744ed1aeb091ac94f0f7562eb02cb27925fbc07..b7557ae0e8ab9b1e88b427ff6ec0d50dcb66a36f 100644 (file)
@@ -95,6 +95,16 @@ vfree(void* ptr)
     __vfree(ptr, piles, CLASS_LEN(piles_names));
 }
 
+void
+vfree_safe(void* ptr)
+{
+    if (!ptr) {
+        return;
+    }
+
+    __vfree(ptr, piles, CLASS_LEN(piles_names));
+}
+
 void*
 valloc_dma(unsigned int size)
 {
index c38ad2bc2517f340c5f55f2d8a84cd2a892a5d8f..d765691a3d622482076d07c161ca414833639b1c 100644 (file)
@@ -1,10 +1,10 @@
 #include <lunaix/block.h>
 #include <lunaix/common.h>
+#include <lunaix/exec.h>
 #include <lunaix/foptions.h>
 #include <lunaix/fs.h>
 #include <lunaix/fs/probe_boot.h>
 #include <lunaix/fs/twifs.h>
-#include <lunaix/ld.h>
 #include <lunaix/lxconsole.h>
 #include <lunaix/mm/cake.h>
 #include <lunaix/mm/pmm.h>
@@ -67,31 +67,11 @@ int
 exec_initd()
 {
     int errno = 0;
-    struct ld_param param;
-    char filename[] = "/mnt/lunaix-os/usr/init";
 
-    ld_create_param(&param, __current, VMS_SELF);
-
-    if ((errno = exec_load_byname(&param, filename, NULL, NULL))) {
+    if (exec_kexecve("/mnt/lunaix-os/usr/init", NULL, NULL)) {
         goto fail;
     }
 
-    // user space
-    asm volatile("movw %0, %%ax\n"
-                 "movw %%ax, %%es\n"
-                 "movw %%ax, %%ds\n"
-                 "movw %%ax, %%fs\n"
-                 "movw %%ax, %%gs\n"
-                 "pushl %0\n"
-                 "pushl %1\n"
-                 "pushl %2\n"
-                 "pushl %3\n"
-                 "retf" ::"i"(UDATA_SEG),
-                 "r"(param.info.stack_top),
-                 "i"(UCODE_SEG),
-                 "r"(param.info.entry)
-                 : "eax", "memory");
-
     fail("should not reach");
 
 fail:
index 23ff6a4dcc3e9a24ae115ebb532f4bed10de17bf..1b22219db4de2d8909237f2f0c735862a413933f 100644 (file)
@@ -1,3 +1,4 @@
+#include <arch/abi.h>
 #include <klibc/string.h>
 #include <lunaix/clock.h>
 #include <lunaix/common.h>
@@ -238,7 +239,7 @@ dup_proc()
     vmm_unmount_pd(VMS_MOUNT_1);
 
     // 正如同fork,返回两次。
-    pcb->intr_ctx.registers.eax = 0;
+    store_retval_to(pcb, 0);
 
     commit_process(pcb);
 
index 9933682a047e49c8c303370c7bbd571ed07c4472..e8683a1b80f46ced290f989a8e60dc8c65712276 100644 (file)
@@ -17,9 +17,10 @@ default_sighandler_term(int signum)
 
 void* default_handlers[_SIG_NUM] = {
     // TODO: 添加默认handler
-    [_SIGINT] = default_sighandler_term,  [_SIGTERM] = default_sighandler_term,
-    [_SIGKILL] = default_sighandler_term, [_SIGSEGV] = default_sighandler_term,
     [_SIGINT] = default_sighandler_term,
+    [_SIGTERM] = default_sighandler_term,
+    [_SIGKILL] = default_sighandler_term,
+    [_SIGSEGV] = default_sighandler_term,
 };
 
 // Referenced in kernel/asm/x86/interrupt.S
@@ -42,6 +43,10 @@ signal_dispatch()
         return 0;
     }
 
+    // TODO: SIG{INT|TERM|KILL|SEGV} should have highest priority.
+    //       Terminate the process right here if any of unmaskable signal is
+    //       set.
+
     if (!__current->sig_handler[sig_selected] &&
         !default_handlers[sig_selected]) {
         // 如果该信号没有handler,则忽略
diff --git a/lunaix-os/usr/uinit.c b/lunaix-os/usr/uinit.c
deleted file mode 100644 (file)
index 0352743..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#define __USR_WRAPPER__
-#include <lunaix/ld.h>
-
-int
-usr_pre_init(struct usr_exec_param* param)
-{
-    // TODO some inits before executing user program
-
-    extern ptr_t environ;
-    environ = (ptr_t)param->envp;
-
-    return 0;
-}
\ No newline at end of file
index c9e2bbc20aa9a43ec6c512b3c9d27e59563ca11c..84fe24ec0183eda8dde63fbe8a4f60da8275c4c2 100644 (file)
@@ -8,17 +8,7 @@
 
 .section .text
     .global _u_start
-    _u_start:
-        movl (%esp), %eax
-        pushl %eax
-        call usr_pre_init
-        jnz 1f
-
-        popl %eax
-
-        pushl 4(%eax)   // argv
-        pushl (%eax)    // argc
-        
+    _u_start:        
         xorl %eax, %eax
         call main