feat: shell and signal demo as loadable user executable
authorMinep <lunaixsky@qq.com>
Sun, 18 Jun 2023 18:08:07 +0000 (19:08 +0100)
committerMinep <lunaixsky@qq.com>
Sun, 18 Jun 2023 18:08:07 +0000 (19:08 +0100)
fix: incorrect offset when mmap segments
refactor: streamline loading of memory-mapped file
other minor refactorings

16 files changed:
lunaix-os/includes/lunaix/mm/mm.h
lunaix-os/includes/lunaix/mm/page.h
lunaix-os/kernel/asm/x86/pfault.c
lunaix-os/kernel/fs/ramfs/ramfs.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/loader/elf.c
lunaix-os/kernel/loader/exec.c
lunaix-os/kernel/mm/mmap.c
lunaix-os/kernel/process/signal.c
lunaix-os/kernel/tty/lxconsole.c
lunaix-os/link/linker.ld
lunaix-os/uprog/init.c
lunaix-os/uprog/sh.c [new file with mode: 0644]
lunaix-os/uprog/signal_demo.c [new file with mode: 0644]
lunaix-os/usr/includes/string.h
lunaix-os/usr/libc/string.c

index 74868b0e9d39781b440edeb7731c1570a38a44eb..24ced3cc9dcce584558e48e74c463c985242f49b 100644 (file)
@@ -65,8 +65,6 @@ struct mm_region
     void** index; // fast reference, to accelerate access to this very region.
 
     void* data;
-    // When a page is mapped and required initialize
-    int (*init_page)(struct mm_region*, void*, off_t);
     // when a region is copied
     void (*region_copied)(struct mm_region*);
     // when a region is unmapped
index 9330274f2cf144e85e90d3e06666d0024a9ee299..8720e1c917a0626a2f64cf13746415ce0c499c26 100644 (file)
@@ -13,6 +13,7 @@
 #define V2P(vaddr) ((ptr_t)(vaddr)-KERNEL_MM_BASE)
 
 #define PG_ALIGN(addr) ((ptr_t)(addr)&0xFFFFF000UL)
+#define PG_MOD(addr) ((ptr_t)(addr) & ~PG_SIZE)
 #define PG_ALIGNED(addr) (!((ptr_t)(addr)&0x00000FFFUL))
 
 #define L1_INDEX(vaddr) (u32_t)(((ptr_t)(vaddr)&0xFFC00000UL) >> 22)
index 610c1cb978fd0dd1031a4d5825b6cbbacc8fbb36..897a7dd2a197a6ac7c1f5d4b66bd8740a8181f9e 100644 (file)
@@ -92,7 +92,8 @@ intr_routine_page_fault(const isr_param* param)
 
         ptr = PG_ALIGN(ptr);
 
-        u32_t offset = (ptr - hit_region->start) + hit_region->foff;
+        u32_t mseg_off = (ptr - hit_region->start);
+        u32_t mfile_off = mseg_off + hit_region->foff;
         uintptr_t pa = pmm_alloc_page(__current->pid, 0);
 
         if (!pa) {
@@ -105,10 +106,8 @@ intr_routine_page_fault(const isr_param* param)
         memset(ptr, 0, PG_SIZE);
 
         int errno = 0;
-        if (hit_region->init_page) {
-            errno = hit_region->init_page(hit_region, ptr, offset);
-        } else {
-            errno = file->ops->read_page(file->inode, ptr, PG_SIZE, offset);
+        if (mseg_off < hit_region->flen) {
+            errno = file->ops->read_page(file->inode, ptr, PG_SIZE, mfile_off);
         }
 
         if (errno < 0) {
index bcffa1655f072b5b805974d2d99afd4c060c4e6a..decc0806d082ac0cfc8699fdf42ea98b4606ace7 100644 (file)
@@ -22,7 +22,7 @@
     case, our rootfs will be something like ext2.
 
     RamFS vs. TwiFS: Indeed, they are both fs that lives in RAM so
-    there is no foundmentally differences. However, TwiFS is designed
+    there is no foundmental differences. However, TwiFS is designed
     to be a 'virtual FIlesystem for KERnel space' (FIKER), so other
     kernel sub-modules can just create node and attach their own
     implementation of read/write, without brothering to create a
index 8a4a8a17e0a9f148f0307e2b6f32f43b27d0558f..6f94b5a7c98a7cbce2d84cb00bd4e671077c179a 100644 (file)
@@ -821,7 +821,7 @@ vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
 
     size_t cpy_size = MIN(dnode->name.len, size - len);
     strncpy(buf + len, dnode->name.value, cpy_size);
-    len += cpy_size;
+    len += cpy_size + !!cpy_size;
 
     return len;
 }
@@ -1322,7 +1322,7 @@ __DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
         }
     }
 
-    buf[len + 1] = '\0';
+    buf[len] = '\0';
 
     ret_ptr = buf;
 
index 241ddf91b253823cb88b5600b3f116cdb7ef020d..f6d494759591a2c6e42c124ff387e405e1cbc9a8 100644 (file)
@@ -7,33 +7,13 @@
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
 
-int
-__elf_populate_mapped(struct mm_region* region, void* pg, off_t segfoff)
-{
-    size_t segsz = region->flen;
-    size_t segmoff = segfoff - region->foff;
-
-    if (segmoff >= segsz) {
-        return 0;
-    }
-
-    struct v_file* file = region->mfile;
-    size_t rdlen = MIN(segsz - segmoff, PG_SIZE);
-
-    if (rdlen == PG_SIZE) {
-        // This is because we want to exploit any optimization on read_page
-        return file->ops->read_page(file->inode, pg, PG_SIZE, segfoff);
-    } else {
-        // we don't want to over-read the segment!
-        return file->ops->read(file->inode, pg, rdlen, segfoff);
-    }
-}
-
 int
 elf_map_segment(struct ld_param* ldparam,
                 struct v_file* elfile,
                 struct elf32_phdr* phdr)
 {
+    assert(PG_ALIGNED(phdr->p_offset));
+
     int proct = 0;
     if ((phdr->p_flags & PF_R)) {
         proct |= PROT_READ;
@@ -45,21 +25,19 @@ elf_map_segment(struct ld_param* ldparam,
         proct |= PROT_EXEC;
     }
 
-    struct mm_region* seg_reg;
     struct mmap_param param = { .vms_mnt = ldparam->vms_mnt,
                                 .pvms = &ldparam->proc->mm,
                                 .proct = proct,
-                                .offset = phdr->p_offset,
+                                .offset = PG_ALIGN(phdr->p_offset),
                                 .mlen = ROUNDUP(phdr->p_memsz, PG_SIZE),
-                                .flen = phdr->p_filesz,
+                                .flen = phdr->p_filesz + PG_MOD(phdr->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);
 
     if (!status) {
-        seg_reg->init_page = __elf_populate_mapped;
-
         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;
index 331cacca5283df528a73b79b2e1d0dca65275061..e5e64fe30d22e0174c918bbb3b5f6399451d02dd 100644 (file)
@@ -128,6 +128,8 @@ exec_load(struct ld_param* param,
                                                .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
         fail("not implemented");
     }
 
index f700fd533179d9528ff84191e6f14402d0f5eca2..383d83e9bad557fd60d8e8af687a008ee1c968e3 100644 (file)
@@ -139,6 +139,15 @@ found:
     return 0;
 }
 
+int
+mem_remap(void** addr_out,
+          struct mm_region** remapped,
+          void* addr,
+          struct v_file* file,
+          struct mmap_param* param)
+{
+}
+
 void
 mem_sync_pages(ptr_t mnt,
                struct mm_region* region,
@@ -288,8 +297,10 @@ __DEFINE_LXSYSCALL3(void*, sys_mmap, void*, addr, size_t, length, va_list, lst)
     if (!addr) {
         addr = UMMAP_START;
     } else if (addr < UMMAP_START || addr + length >= UMMAP_END) {
-        errno = ENOMEM;
-        goto done;
+        if (!(options & (MAP_FIXED | MAP_FIXED_NOREPLACE))) {
+            errno = ENOMEM;
+            goto done;
+        }
     }
 
     struct v_fd* vfd;
index 0f43b1f65216adc7d1dfadae52f365318b40248e..9933682a047e49c8c303370c7bbd571ed07c4472 100644 (file)
@@ -22,7 +22,6 @@ void* default_handlers[_SIG_NUM] = {
     [_SIGINT] = default_sighandler_term,
 };
 
-volatile struct proc_sigstate __temp_save;
 // Referenced in kernel/asm/x86/interrupt.S
 void*
 signal_dispatch()
@@ -79,6 +78,7 @@ signal_dispatch()
 
         解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
     */
+    static volatile struct proc_sigstate __temp_save;
     __temp_save.proc_regs = __current->intr_ctx;
     memcpy(__temp_save.fxstate, __current->fxstate, 512);
 
index adf577a6ed5339c6d98b22229abe6d7d67460cb8..0d7439be4542554b427ad998f9690d7c65fc9c85 100644 (file)
@@ -1,3 +1,14 @@
+/**
+ * @file lxconsole.c
+ * @author Lunaixsky (lunaxisky@qq.com)
+ * @brief Provides simple terminal support
+ * @version 0.1
+ * @date 2023-06-18
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
 #include <klibc/string.h>
 #include <lunaix/device.h>
 #include <lunaix/input.h>
index ba3a3853a232d4fb4c9bd10df8a1175f660ff367..7ea0804fe2d604444b3824e0d6fa258aa66e2289 100644 (file)
@@ -47,11 +47,6 @@ SECTIONS {
     }
     __usrtext_end = ALIGN(4K);
 
-    .bss BLOCK(4K) : AT ( ADDR(.bss) - 0xC0000000 ) {
-        build/obj/kernel/*.o (.bss)
-        build/obj/hal/*.o (.bss)
-    }
-
     .data BLOCK(4k) : AT ( ADDR(.data) - 0xC0000000 ) {
         build/obj/kernel/*.o (.data)
         build/obj/hal/*.o (.data)
@@ -66,5 +61,10 @@ SECTIONS {
         build/obj/arch/x86/*.o (.kpg)
     }
 
+    .bss BLOCK(4K) : AT ( ADDR(.bss) - 0xC0000000 ) {
+        build/obj/kernel/*.o (.bss)
+        build/obj/hal/*.o (.bss)
+    }
+
     __kernel_end = ALIGN(4K);
 }
\ No newline at end of file
index dd083add12be17fe2f84968ee6b83809bfd57290..a7265c0e350c4c9b54187d5d7a2b94d77c8faf8b 100644 (file)
@@ -22,7 +22,7 @@ main(int argc, const char** argv)
 
     pid_t pid;
     if (!(pid = fork())) {
-        int err = execve("/mnt/lunaix-os/usr/ls", NULL, NULL);
+        int err = execve("/mnt/lunaix-os/usr/sh", NULL, NULL);
         printf("fail to execute (%d)\n", err);
         _exit(err);
     }
diff --git a/lunaix-os/uprog/sh.c b/lunaix-os/uprog/sh.c
new file mode 100644 (file)
index 0000000..4e0c6f6
--- /dev/null
@@ -0,0 +1,167 @@
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+char pwd[512];
+char cat_buf[1024];
+
+/*
+    Simple shell - (actually this is not even a shell)
+    It just to make the testing more easy.
+*/
+
+#define WS_CHAR(c)                                                             \
+    (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == '\r')
+
+void
+strrtrim(char* str)
+{
+    size_t l = strlen(str);
+    while (l < (size_t)-1) {
+        char c = str[l];
+        if (!c || WS_CHAR(c)) {
+            l--;
+            continue;
+        }
+        break;
+    }
+    str[l + 1] = '\0';
+}
+
+char*
+strltrim_safe(char* str)
+{
+    size_t l = 0;
+    char c = 0;
+    while ((c = str[l]) && WS_CHAR(c)) {
+        l++;
+    }
+
+    if (!l)
+        return str;
+    return strcpy(str, str + l);
+}
+
+void
+parse_cmdline(char* line, char** cmd, char** arg_part)
+{
+    strrtrim(line);
+    line = strltrim_safe(line);
+    int l = 0;
+    char c = 0;
+    while ((c = line[l])) {
+        if (c == ' ') {
+            line[l++] = 0;
+            break;
+        }
+        l++;
+    }
+    *cmd = line;
+    *arg_part = strltrim_safe(line + l);
+}
+
+void
+sh_printerr()
+{
+    switch (errno) {
+        case 0:
+            break;
+        case ENOTDIR:
+            printf("Error: Not a directory\n");
+            break;
+        case ENOENT:
+            printf("Error: No such file or directory\n");
+            break;
+        case EINVAL:
+            printf("Error: Invalid parameter or operation\n");
+            break;
+        case ENOTSUP:
+            printf("Error: Not supported\n");
+            break;
+        case EROFS:
+            printf("Error: File system is read only\n");
+            break;
+        case ENOMEM:
+            printf("Error: Out of memory\n");
+            break;
+        case EISDIR:
+            printf("Error: This is a directory\n");
+            break;
+        default:
+            printf("Error: (%d)\n", errno);
+            break;
+    }
+}
+
+void
+sigint_handle(int signum)
+{
+    return;
+}
+
+void
+sh_exec(const char* name, const char** argv)
+{
+    if (!strcmp(name, "cd")) {
+        chdir(argv[0]);
+        sh_printerr();
+        return;
+    }
+
+    pid_t p;
+    if (!(p = fork())) {
+        if (execve(name, argv, NULL)) {
+            sh_printerr();
+        }
+        _exit(1);
+    }
+    setpgid(p, getpgid());
+    waitpid(p, NULL, 0);
+}
+
+void
+sh_loop()
+{
+    char buf[512];
+    char *cmd, *argpart;
+    signal(SIGINT, sigint_handle);
+
+    // set our shell as foreground process
+    // (unistd.h:tcsetpgrp is essentially a wrapper of this)
+    // stdout (by default, unless user did smth) is the tty we are currently at
+    ioctl(stdout, TIOCSPGRP, getpgid());
+
+    while (1) {
+        getcwd(pwd, 512);
+        printf("[\033[2m%s\033[39;49m]$ ", pwd);
+        size_t sz = read(stdin, buf, 511);
+        if (sz < 0) {
+            printf("fail to read user input (%d)\n", geterrno());
+            return;
+        }
+        buf[sz] = '\0';
+        parse_cmdline(buf, &cmd, &argpart);
+        if (cmd[0] == 0) {
+            printf("\n");
+            goto cont;
+        }
+        // cmd=="exit"
+        if (*(unsigned int*)cmd == 0x74697865U) {
+            break;
+        }
+        sh_exec(cmd, NULL);
+    cont:
+        printf("\n");
+    }
+}
+
+void
+main()
+{
+    printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
+    sh_loop();
+    _exit(0);
+}
\ No newline at end of file
diff --git a/lunaix-os/uprog/signal_demo.c b/lunaix-os/uprog/signal_demo.c
new file mode 100644 (file)
index 0000000..ef261ab
--- /dev/null
@@ -0,0 +1,72 @@
+#include <signal.h>
+
+void
+sigchild_handler(int signum)
+{
+    printf("SIGCHLD received\n");
+}
+
+void
+sigsegv_handler(int signum)
+{
+    pid_t pid = getpid();
+    printf("SIGSEGV received on process %d\n", pid);
+    _exit(signum);
+}
+
+void
+sigalrm_handler(int signum)
+{
+    pid_t pid = getpid();
+    printf("I, pid %d, have received an alarm!\n", pid);
+}
+
+void
+main()
+{
+    signal(SIGCHLD, sigchild_handler);
+    signal(SIGSEGV, sigsegv_handler);
+    signal(SIGALRM, sigalrm_handler);
+
+    alarm(5);
+
+    int status;
+    pid_t p = 0;
+
+    printf("Child sleep 3s, parent pause.\n");
+    if (!fork()) {
+        sleep(3);
+        _exit(0);
+    }
+
+    pause();
+
+    printf("Parent resumed on SIGCHILD\n");
+
+    for (int i = 0; i < 5; i++) {
+        pid_t pid = 0;
+        if (!(pid = fork())) {
+            signal(SIGSEGV, sigsegv_handler);
+            sleep(i);
+            if (i == 3) {
+                i = *(int*)0xdeadc0de; // seg fault!
+            }
+            printf("%d\n", i);
+            _exit(0);
+        }
+        printf("Forked %d\n", pid);
+    }
+
+    while ((p = wait(&status)) >= 0) {
+        short code = WEXITSTATUS(status);
+        if (WIFSIGNALED(status)) {
+            printf("Process %d terminated by signal, exit_code: %d\n", p, code);
+        } else if (WIFEXITED(status)) {
+            printf("Process %d exited with code %d\n", p, code);
+        } else {
+            printf("Process %d aborted with code %d\n", p, code);
+        }
+    }
+
+    printf("done\n");
+}
\ No newline at end of file
index 2b5799a15fc100ac85b50ce3768d40fc906b6201..7383a0f2d14d6c6710d0eb0f406446b8c646fb84 100644 (file)
@@ -18,4 +18,7 @@ strchr(const char* str, int character);
 char*
 strcpy(char* dest, const char* src);
 
+int
+strcmp(const char* s1, const char* s2);
+
 #endif /* __LUNAIX_STRING_H */
index 280cbbe3c8b18fea2440d3010293a1aa3f3acfd6..726437c15a27be883ee4791aed3af876db1c9965 100644 (file)
@@ -55,3 +55,13 @@ strcpy(char* dest, const char* src)
     dest[i] = '\0';
     return dest;
 }
+
+int
+strcmp(const char* a, const char* b)
+{
+    while (*a && *a == *b) {
+        a++;
+        b++;
+    }
+    return *a - *b;
+}
\ No newline at end of file