From 75339638bc5f21f13d3475374ecbd91065a427c3 Mon Sep 17 00:00:00 2001 From: Minep Date: Sun, 18 Jun 2023 19:08:07 +0100 Subject: [PATCH] feat: shell and signal demo as loadable user executable fix: incorrect offset when mmap segments refactor: streamline loading of memory-mapped file other minor refactorings --- lunaix-os/includes/lunaix/mm/mm.h | 2 - lunaix-os/includes/lunaix/mm/page.h | 1 + lunaix-os/kernel/asm/x86/pfault.c | 9 +- lunaix-os/kernel/fs/ramfs/ramfs.c | 2 +- lunaix-os/kernel/fs/vfs.c | 4 +- lunaix-os/kernel/loader/elf.c | 32 +----- lunaix-os/kernel/loader/exec.c | 2 + lunaix-os/kernel/mm/mmap.c | 15 ++- lunaix-os/kernel/process/signal.c | 2 +- lunaix-os/kernel/tty/lxconsole.c | 11 ++ lunaix-os/link/linker.ld | 10 +- lunaix-os/uprog/init.c | 2 +- lunaix-os/uprog/sh.c | 167 ++++++++++++++++++++++++++++ lunaix-os/uprog/signal_demo.c | 72 ++++++++++++ lunaix-os/usr/includes/string.h | 3 + lunaix-os/usr/libc/string.c | 10 ++ 16 files changed, 298 insertions(+), 46 deletions(-) create mode 100644 lunaix-os/uprog/sh.c create mode 100644 lunaix-os/uprog/signal_demo.c diff --git a/lunaix-os/includes/lunaix/mm/mm.h b/lunaix-os/includes/lunaix/mm/mm.h index 74868b0..24ced3c 100644 --- a/lunaix-os/includes/lunaix/mm/mm.h +++ b/lunaix-os/includes/lunaix/mm/mm.h @@ -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 diff --git a/lunaix-os/includes/lunaix/mm/page.h b/lunaix-os/includes/lunaix/mm/page.h index 9330274..8720e1c 100644 --- a/lunaix-os/includes/lunaix/mm/page.h +++ b/lunaix-os/includes/lunaix/mm/page.h @@ -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) diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 610c1cb..897a7dd 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -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) { diff --git a/lunaix-os/kernel/fs/ramfs/ramfs.c b/lunaix-os/kernel/fs/ramfs/ramfs.c index bcffa16..decc080 100644 --- a/lunaix-os/kernel/fs/ramfs/ramfs.c +++ b/lunaix-os/kernel/fs/ramfs/ramfs.c @@ -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 diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index 8a4a8a1..6f94b5a 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -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; diff --git a/lunaix-os/kernel/loader/elf.c b/lunaix-os/kernel/loader/elf.c index 241ddf9..f6d4947 100644 --- a/lunaix-os/kernel/loader/elf.c +++ b/lunaix-os/kernel/loader/elf.c @@ -7,33 +7,13 @@ #include #include -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, ¶m); 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; diff --git a/lunaix-os/kernel/loader/exec.c b/lunaix-os/kernel/loader/exec.c index 331cacc..e5e64fe 100644 --- a/lunaix-os/kernel/loader/exec.c +++ b/lunaix-os/kernel/loader/exec.c @@ -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"); } diff --git a/lunaix-os/kernel/mm/mmap.c b/lunaix-os/kernel/mm/mmap.c index f700fd5..383d83e 100644 --- a/lunaix-os/kernel/mm/mmap.c +++ b/lunaix-os/kernel/mm/mmap.c @@ -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; diff --git a/lunaix-os/kernel/process/signal.c b/lunaix-os/kernel/process/signal.c index 0f43b1f..9933682 100644 --- a/lunaix-os/kernel/process/signal.c +++ b/lunaix-os/kernel/process/signal.c @@ -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); diff --git a/lunaix-os/kernel/tty/lxconsole.c b/lunaix-os/kernel/tty/lxconsole.c index adf577a..0d7439b 100644 --- a/lunaix-os/kernel/tty/lxconsole.c +++ b/lunaix-os/kernel/tty/lxconsole.c @@ -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 #include #include diff --git a/lunaix-os/link/linker.ld b/lunaix-os/link/linker.ld index ba3a385..7ea0804 100644 --- a/lunaix-os/link/linker.ld +++ b/lunaix-os/link/linker.ld @@ -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 diff --git a/lunaix-os/uprog/init.c b/lunaix-os/uprog/init.c index dd083ad..a7265c0 100644 --- a/lunaix-os/uprog/init.c +++ b/lunaix-os/uprog/init.c @@ -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 index 0000000..4e0c6f6 --- /dev/null +++ b/lunaix-os/uprog/sh.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include + +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 or 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 index 0000000..ef261ab --- /dev/null +++ b/lunaix-os/uprog/signal_demo.c @@ -0,0 +1,72 @@ +#include + +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 diff --git a/lunaix-os/usr/includes/string.h b/lunaix-os/usr/includes/string.h index 2b5799a..7383a0f 100644 --- a/lunaix-os/usr/includes/string.h +++ b/lunaix-os/usr/includes/string.h @@ -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 */ diff --git a/lunaix-os/usr/libc/string.c b/lunaix-os/usr/libc/string.c index 280cbbe..726437c 100644 --- a/lunaix-os/usr/libc/string.c +++ b/lunaix-os/usr/libc/string.c @@ -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 -- 2.27.0