Jelajahi Sumber

Merge branch 'dev'

greatbridf 2 tahun lalu
induk
melakukan
d3f2ae9dcf
68 mengubah file dengan 2873 tambahan dan 1436 penghapusan
  1. 11 10
      CMakeLists.txt
  2. 5 2
      gblibc/CMakeLists.txt
  3. 15 0
      gblibc/include/bits/ioctl.h
  4. 18 0
      gblibc/include/ctype.h
  5. 35 0
      gblibc/include/dirent.h
  6. 8 0
      gblibc/include/fcntl.h
  7. 2 0
      gblibc/include/stdio.h
  8. 16 0
      gblibc/include/sys/ioctl.h
  9. 2 0
      gblibc/include/sys/types.h
  10. 23 2
      gblibc/include/unistd.h
  11. 21 10
      gblibc/private-include/syscall.h
  12. 1 1
      gblibc/src/crt0.s
  13. 25 0
      gblibc/src/ctype.c
  14. 71 0
      gblibc/src/dirent.c
  15. 14 6
      gblibc/src/stdio.c
  16. 91 1
      gblibc/src/unistd.c
  17. 0 24
      include/asm/boot.h
  18. 4 2
      include/asm/sys.h
  19. 10 1
      include/kernel/errno.h
  20. 13 25
      include/kernel/event/evtqueue.hpp
  21. 8 15
      include/kernel/mem.h
  22. 133 117
      include/kernel/mm.hpp
  23. 181 51
      include/kernel/process.hpp
  24. 70 0
      include/kernel/signal.hpp
  25. 1 1
      include/kernel/syscall.hpp
  26. 14 1
      include/kernel/tty.hpp
  27. 52 5
      include/kernel/vfs.hpp
  28. 0 10
      include/kernel_main.hpp
  29. 186 18
      include/types/allocator.hpp
  30. 3 3
      include/types/bitmap.h
  31. 10 0
      include/types/buffer.hpp
  32. 27 1
      include/types/elf.hpp
  33. 6 2
      include/types/list.hpp
  34. 65 52
      include/types/map.hpp
  35. 1 1
      include/types/size.h
  36. 1 0
      include/types/vector.hpp
  37. 147 10
      pretty-print.py
  38. 0 30
      src/asm/a20.s
  39. 15 19
      src/asm/interrupt.s
  40. 1 0
      src/asm/port_io.s
  41. 9 6
      src/asm/sys.s
  42. 120 89
      src/boot.s
  43. 21 11
      src/fs/fat.cpp
  44. 77 26
      src/kernel.ld
  45. 29 38
      src/kernel/event/event.cpp
  46. 6 4
      src/kernel/hw/ata.cpp
  47. 1 0
      src/kernel/hw/serial.cpp
  48. 1 0
      src/kernel/hw/timer.c
  49. 65 35
      src/kernel/interrupt.cpp
  50. 216 350
      src/kernel/mem.cpp
  51. 149 28
      src/kernel/process.cpp
  52. 0 0
      src/kernel/signal.cpp
  53. 276 96
      src/kernel/syscall.cpp
  54. 50 20
      src/kernel/tty.cpp
  55. 103 3
      src/kernel/vfs.cpp
  56. 0 185
      src/kernel_main.cpp
  57. 120 0
      src/kinit.cpp
  58. 2 2
      src/mbr.S
  59. 3 3
      src/types/bitmap.c
  60. 56 13
      src/types/elf.cpp
  61. 0 9
      src/types/libstdcpp.cpp
  62. 4 4
      user-space-program/CMakeLists.txt
  63. 2 2
      user-space-program/hello-world.s
  64. 20 0
      user-space-program/init.c
  65. 3 3
      user-space-program/interrupt-test.s
  66. 168 0
      user-space-program/lazybox.c
  67. 0 27
      user-space-program/script.ld
  68. 66 62
      user-space-program/sh.c

+ 11 - 10
CMakeLists.txt

@@ -29,14 +29,13 @@ add_subdirectory(gblibc)
 add_subdirectory(user-space-program)
 
 set(BOOTLOADER_SOURCES src/boot.s
-                       src/asm/a20.s
                        src/asm/interrupt.s
                        src/asm/port_io.s
                        src/asm/sys.s
                        )
 
 set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
-                        src/kernel_main.cpp
+                        src/kinit.cpp
                         src/kernel/errno.c
                         src/kernel/interrupt.cpp
                         src/kernel/process.cpp
@@ -50,10 +49,10 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/kernel/hw/serial.cpp
                         src/kernel/hw/timer.c
                         src/kernel/event/event.cpp
+                        src/kernel/signal.cpp
                         src/types/bitmap.c
                         src/types/elf.cpp
                         src/types/libstdcpp.cpp
-                        include/asm/boot.h
                         include/asm/port_io.h
                         include/asm/sys.h
                         include/fs/fat.hpp
@@ -68,6 +67,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/kernel/mm.hpp
                         include/kernel/vfs.hpp
                         include/kernel/vga.hpp
+                        include/kernel/signal.hpp
                         include/kernel/hw/ata.hpp
                         include/kernel/hw/keyboard.h
                         include/kernel/hw/port.hpp
@@ -92,7 +92,6 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/vector.hpp
                         include/types/function.hpp
                         include/kernel/log.hpp
-                        include/kernel_main.hpp
                         )
 
 add_executable(kernel.out ${KERNEL_MAIN_SOURCES} ${BOOTLOADER_SOURCES})
@@ -122,12 +121,14 @@ add_custom_target(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_BIN} boot.img
     COMMAND mkfs.fat --offset=2048 -v -n SYSTEM boot.img
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/hello-world.out ::hello.out
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/interrupt-test.out ::int.out
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/stack-test.out ::stack.out
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/init.out ::init.elf
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/sh.out ::sh.elf
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/priv-test.out ::priv.elf
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/hello-world.out ::hello
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/interrupt-test.out ::int
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/stack-test.out ::stack
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/init.out ::init
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/sh.out ::sh
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/priv-test.out ::priv
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/lazybox.out ::lazybox
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/lazybox.out ::pwd
 )
 
 add_custom_command(OUTPUT run

+ 5 - 2
gblibc/CMakeLists.txt

@@ -10,12 +10,15 @@ add_library(gblibc STATIC
     src/unistd.c
     src/wait.c
     src/assert.c
+    src/dirent.c
+    src/ctype.c
 )
 
+file(GLOB_RECURSE GBLIBC_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
 target_include_directories(gblibc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
                                   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/private-include)
 
 set_target_properties(gblibc PROPERTIES PRIVATE_HEADER
     "private-include/devutil.h,private-include/syscall.h")
-set_target_properties(gblibc PROPERTIES PUBLIC_HEADER
-    "include/stdio.h,include/stdint.h,include/stdarg.h,include/string.h,include/unistd.h,include/sys/types.h,include/sys/wait.h,include/fcntl.h,include/assert.h")
+set_target_properties(gblibc PROPERTIES PUBLIC_HEADER "${GBLIBC_PUBLIC_HEADERS}")

+ 15 - 0
gblibc/include/bits/ioctl.h

@@ -0,0 +1,15 @@
+#ifndef __GBLIBC_BITS_IOCTL_H_
+#define __GBLIBC_BITS_IOCTL_H_
+
+#define TIOCSPGRP (0)
+#define TIOCGPGRP (1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 18 - 0
gblibc/include/ctype.h

@@ -0,0 +1,18 @@
+#ifndef __GBLIBC_CTYPE_H_
+#define __GBLIBC_CTYPE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int islower(int c);
+int isupper(int c);
+
+int tolower(int c);
+int toupper(int c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 35 - 0
gblibc/include/dirent.h

@@ -0,0 +1,35 @@
+#ifndef __GBLIBC_DIRENT_H_
+#define __GBLIBC_DIRENT_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dirent {
+    ino_t d_ino;
+    off_t d_off;
+    unsigned short d_reclen;
+    unsigned char d_type;
+    char d_name[256];
+};
+
+typedef struct _DIR {
+    int fd;
+    struct dirent dent;
+    char buffer[232];
+    int bpos;
+    int blen;
+} DIR;
+
+DIR* opendir(const char* name);
+DIR* fdopendir(int fd);
+
+struct dirent* readdir(DIR* dirp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 8 - 0
gblibc/include/fcntl.h

@@ -3,6 +3,14 @@
 
 #include <stdint.h>
 
+#define O_CREAT (1 << 0)
+#define O_RDONLY (1 << 1)
+#define O_WRONLY (1 << 2)
+#define O_RDWR (1 << 3)
+#define O_DIRECTORY (1 << 4)
+#define O_APPEND (1 << 5)
+#define O_TRUNC (1 << 6)
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 2 - 0
gblibc/include/stdio.h

@@ -1,6 +1,7 @@
 #ifndef __GBLIBC_STDIO_H_
 #define __GBLIBC_STDIO_H_
 
+#include <stdarg.h>
 #include <stdint.h>
 
 #undef EOF
@@ -10,6 +11,7 @@
 extern "C" {
 #endif
 
+int vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args);
 int snprintf(char* buf, size_t bufsize, const char* fmt, ...);
 
 #ifdef __cplusplus

+ 16 - 0
gblibc/include/sys/ioctl.h

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_SYS_IOCTL_H_
+#define __GBLIBC_SYS_IOCTL_H_
+
+#include <bits/ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ioctl(int fd, unsigned long request, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 2 - 0
gblibc/include/sys/types.h

@@ -8,6 +8,8 @@ extern "C" {
 #endif
 
 typedef int pid_t;
+typedef uint32_t ino_t;
+typedef int32_t off_t;
 
 #ifdef __cplusplus
 }

+ 23 - 2
gblibc/include/unistd.h

@@ -6,9 +6,9 @@
 #undef STDOUT_FILENO
 #undef STDIN_FILENO
 #undef STDERR_FILENO
-#define STDOUT_FILENO (0)
 #define STDIN_FILENO (0)
-#define STDERR_FILENO (0)
+#define STDOUT_FILENO (1)
+#define STDERR_FILENO (2)
 
 #ifdef __cplusplus
 extern "C" {
@@ -17,12 +17,33 @@ extern "C" {
 ssize_t read(int fd, void* buf, size_t count);
 ssize_t write(int fd, const void* buf, size_t count);
 
+int dup(int oldfd);
+int dup2(int oldfd, int newfd);
+
+int pipe(int pipefd[2]);
+
+int close(int fd);
+
 void __attribute__((noreturn)) _exit(int code);
 pid_t fork(void);
 int execve(const char* pathname, char* const argv[], char* const envp[]);
 
 unsigned int sleep(unsigned int seconds);
 
+int chdir(const char* path);
+char* getcwd(char* buf, size_t bufsize);
+
+pid_t getpid(void);
+pid_t getppid(void);
+
+int setpgid(pid_t pid, pid_t pgid);
+
+pid_t setsid(void);
+pid_t getsid(pid_t pid);
+
+pid_t tcgetpgrp(int fd);
+int tcsetpgrp(int fd, pid_t pgrp);
+
 #ifdef __cplusplus
 }
 #endif

+ 21 - 10
gblibc/private-include/syscall.h

@@ -3,16 +3,27 @@
 
 #include <stdint.h>
 
-#define SYS_fork (0x00)
-#define SYS_write (0x01)
-#define SYS_sleep (0x02)
-#define SYS_crash (0x03)
-#define SYS_exec (0x04)
-#define SYS_exit (0x05)
-#define SYS_wait (0x06)
-#define SYS_read (0x07)
-#define SYS_getdents (0x08)
-#define SYS_open (0x09)
+#define SYS_read (0)
+#define SYS_write (1)
+#define SYS_open (2)
+#define SYS_close (3)
+#define SYS_ioctl (16)
+#define SYS_pipe (22)
+#define SYS_dup (32)
+#define SYS_dup2 (33)
+#define SYS_sleep (35)
+#define SYS_getpid (39)
+#define SYS_fork (57)
+#define SYS_execve (59)
+#define SYS_exit (60)
+#define SYS_wait (61)
+#define SYS_getdents (78)
+#define SYS_getcwd (79)
+#define SYS_chdir (80)
+#define SYS_setpgid (109)
+#define SYS_getppid (110)
+#define SYS_setsid (112)
+#define SYS_getsid (124)
 
 #ifdef __cplusplus
 extern "C" {

+ 1 - 1
gblibc/src/crt0.s

@@ -23,5 +23,5 @@ _start:
     call main
 
     movl %eax, %edi  # code
-    movl $0x05, %eax # SYS_exit
+    movl $60, %eax # SYS_exit
     int $0x80        # syscall

+ 25 - 0
gblibc/src/ctype.c

@@ -0,0 +1,25 @@
+#include <ctype.h>
+
+int islower(int c)
+{
+    return c >= 'a' && c <= 'z';
+}
+
+int isupper(int c)
+{
+    return c >= 'A' && c <= 'Z';
+}
+
+int tolower(int c)
+{
+    if (isupper(c))
+        return c - 'A' + 'a';
+    return c;
+}
+
+int toupper(int c)
+{
+    if (islower(c))
+        return c - 'a' + 'A';
+    return c;
+}

+ 71 - 0
gblibc/src/dirent.c

@@ -0,0 +1,71 @@
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <syscall.h>
+
+DIR* opendir(const char* name)
+{
+    // TODO: set flags
+    int fd = open(name, O_DIRECTORY);
+
+    if (fd < 0)
+        return NULL;
+
+    return fdopendir(fd);
+}
+
+DIR* fdopendir(int fd)
+{
+    static DIR dirs[64];
+    static int next = 0;
+
+    dirs[next].fd = fd;
+    dirs[next].bpos = 0;
+
+    return dirs + next++;
+}
+
+struct kernel_dirent {
+    ino_t d_ino; // inode number
+    uint32_t d_off; // ignored
+    uint16_t d_reclen; // length of this struct user_dirent
+    char d_name[1]; // file name with a padding zero
+    // uint8_t d_type; // file type, with offset of (d_reclen - 1)
+};
+
+size_t fill_dirent(struct dirent* dent, char* buffer, size_t bpos)
+{
+    struct kernel_dirent* dp = (struct kernel_dirent*)(buffer + bpos);
+    dent->d_ino = dp->d_ino;
+    dent->d_off = dp->d_off;
+    dent->d_reclen = dp->d_reclen;
+    dent->d_type = buffer[bpos + dp->d_reclen - 1];
+    strncpy(dent->d_name, dp->d_name, sizeof(dent->d_name));
+    dent->d_name[sizeof(dent->d_name) - 1] = 0;
+
+    return bpos + dp->d_reclen;
+}
+
+struct dirent* readdir(DIR* dirp)
+{
+    if (dirp->bpos) {
+        if (dirp->bpos >= dirp->blen) {
+            dirp->bpos = 0;
+        } else {
+            goto fill;
+        }
+    }
+
+    dirp->blen = syscall3(SYS_getdents,
+        dirp->fd,
+        (uint32_t)dirp->buffer,
+        sizeof(dirp->buffer)
+    );
+
+    if (dirp->blen <= 0)
+        return NULL;
+
+fill:
+    dirp->bpos = fill_dirent(&dirp->dent, dirp->buffer, dirp->bpos);
+    return &dirp->dent;
+}

+ 14 - 6
gblibc/src/stdio.c

@@ -1,5 +1,6 @@
 #include <devutil.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdarg.h>
 
 // where n is in the range of [0, 9]
@@ -236,12 +237,21 @@ snprint_char(
     return sizeof(c);
 }
 
-int snprintf(char* buf, size_t buf_size, const char* fmt, ...)
+int snprintf(char* buf, size_t bufsize, const char* fmt, ...)
 {
-    ssize_t n_write = 0;
+    va_list lst;
+    va_start(lst, fmt);
+
+    int ret = vsnprintf(buf, bufsize, fmt, lst);
+
+    va_end(lst);
+
+    return ret;
+}
 
-    va_list arg;
-    va_start(arg, fmt);
+int vsnprintf(char* buf, size_t buf_size, const char* fmt, va_list arg)
+{
+    ssize_t n_write = 0;
 
     for (char c; (c = *fmt) != 0x00; ++fmt) {
         if (c == '%') {
@@ -339,7 +349,5 @@ int snprintf(char* buf, size_t buf_size, const char* fmt, ...)
     if (buf_size > 0)
         *buf = 0x00;
 
-    va_end(arg);
-
     return n_write;
 }

+ 91 - 1
gblibc/src/unistd.c

@@ -1,3 +1,5 @@
+#include <stdarg.h>
+#include <sys/ioctl.h>
 #include <unistd.h>
 #include <syscall.h>
 
@@ -11,6 +13,26 @@ ssize_t write(int fd, const void* buf, size_t count)
     return syscall3(SYS_write, fd, (uint32_t)buf, count);
 }
 
+int dup(int oldfd)
+{
+    return syscall1(SYS_dup, oldfd);
+}
+
+int dup2(int oldfd, int newfd)
+{
+    return syscall2(SYS_dup2, oldfd, newfd);
+}
+
+int pipe(int pipefd[2])
+{
+    return syscall1(SYS_pipe, (uint32_t)pipefd);
+}
+
+int close(int fd)
+{
+    return syscall1(SYS_close, fd);
+}
+
 _Noreturn void _exit(int code)
 {
     (void)syscall1(SYS_exit, code);
@@ -25,10 +47,78 @@ pid_t fork(void)
 
 int execve(const char* pathname, char* const argv[], char* const envp[])
 {
-    return syscall3(SYS_exec, (uint32_t)pathname, (uint32_t)argv, (uint32_t)envp);
+    return syscall3(SYS_execve, (uint32_t)pathname, (uint32_t)argv, (uint32_t)envp);
 }
 
 unsigned int sleep(unsigned int seconds)
 {
     return syscall1(SYS_sleep, seconds);
 }
+
+int chdir(const char* path)
+{
+    return syscall1(SYS_chdir, (uint32_t)path);
+}
+
+char* getcwd(char* buf, size_t bufsize)
+{
+    return (char*)syscall2(SYS_getcwd, (uint32_t)buf, bufsize);
+}
+
+pid_t getpid(void)
+{
+    return syscall0(SYS_getpid);
+}
+
+pid_t getppid(void)
+{
+    return syscall0(SYS_getppid);
+}
+
+int setpgid(pid_t pid, pid_t pgid)
+{
+    return syscall2(SYS_setpgid, pid, pgid);
+}
+
+pid_t setsid(void)
+{
+    return syscall0(SYS_setsid);
+}
+
+pid_t getsid(pid_t pid)
+{
+    return syscall1(SYS_getsid, pid);
+}
+
+pid_t tcgetpgrp(int fd)
+{
+    pid_t pgrp;
+    return ioctl(fd, TIOCGPGRP, &pgrp);
+}
+
+int tcsetpgrp(int fd, pid_t pgrp)
+{
+    return ioctl(fd, TIOCSPGRP, &pgrp);
+}
+
+int ioctl(int fd, unsigned long request, ...)
+{
+    int ret = -1;
+
+    va_list args;
+    va_start(args, request);
+
+    switch (request) {
+    case TIOCGPGRP:
+        ret = syscall3(SYS_ioctl, fd, request, va_arg(args, uint32_t));
+        break;
+    case TIOCSPGRP:
+        ret = syscall3(SYS_ioctl, fd, request, va_arg(args, uint32_t));
+        break;
+    default:
+        break;
+    }
+
+    va_end(args);
+    return ret;
+}

+ 0 - 24
include/asm/boot.h

@@ -1,24 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-
-#define KERNEL_EARLY_STACK_ADDR ((phys_ptr_t)0x01000000)
-#define KERNEL_EARLY_STACK_SIZE ((size_t)0x100000)
-
-struct __attribute__((__packed__)) gdt_descriptor {
-    uint16_t size;
-    uint32_t address;
-};
-
-extern struct gdt_descriptor asm_gdt_descriptor;
-
-extern struct mem_size_info asm_mem_size_info;
-
-extern uint8_t asm_e820_mem_map[1024];
-extern uint32_t asm_e820_mem_map_count;
-extern uint32_t asm_e820_mem_map_entry_size;
-
-extern uint32_t asm_kernel_size;
-
-extern uint32_t bss_section_start_addr;
-extern uint32_t bss_section_end_addr;

+ 4 - 2
include/asm/sys.h

@@ -7,7 +7,7 @@
 extern "C" {
 #endif
 
-void asm_switch_pd(pd_t pd_addr);
+void asm_switch_pd(page_t pd_addr);
 void asm_enable_paging(pd_t pd_addr);
 
 pptr_t current_pd(void);
@@ -18,7 +18,9 @@ void asm_load_gdt(uint32_t limit, pptr_t addr);
 
 void asm_load_tr(uint16_t index);
 
-extern void* __real_kernel_end;
+extern const uint32_t kernel_size;
+extern char* const bss_addr;
+extern const uint32_t bss_len;
 
 #ifdef __cplusplus
 }

+ 10 - 1
include/kernel/errno.h

@@ -1,4 +1,5 @@
-#pragma once
+#ifndef __GBOS_ERRNO_H
+#define __GBOS_ERRNO_H
 
 #include <types/types.h>
 
@@ -22,3 +23,11 @@ extern uint32_t* _get_errno(void);
 #define ENOTDIR (1 << 5)
 #define ENOTFOUND (1 << 6)
 #define ECHILD (1 << 7)
+#define EBADF (1 << 8)
+#define EPERM (1 << 9)
+#define ESRCH (1 << 10)
+#define EINTR (1 << 11)
+#define EPIPE (1 << 12)
+#define ENOTTY (1 << 13)
+
+#endif

+ 13 - 25
include/kernel/event/evtqueue.hpp

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <types/cplusplus.hpp>
 #include <types/list.hpp>
 #include <types/lock.hpp>
 
@@ -8,38 +9,25 @@ struct thread;
 
 namespace kernel {
 
-struct evt {
-    thread* emitter;
-    void* data1;
-    void* data2;
-    void* data3;
-};
-
-class evtqueue {
-public:
-    // TODO: use small object allocator
-    using evt_list_type = types::list<evt>;
-    using subscriber_list_type = types::list<thread*>;
-
+class cond_var : public types::non_copyable {
 private:
+    using list_type = types::list<thread*>;
+
     types::mutex m_mtx;
-    evt_list_type m_evts;
-    subscriber_list_type m_subscribers;
+    list_type m_subscribers;
 
 public:
-    evtqueue(void) = default;
-    evtqueue(const evtqueue&) = delete;
-    evtqueue(evtqueue&&);
+    cond_var(void) = default;
 
-    void push(evt&& event);
-    evt front();
-    const evt* peek(void) const;
+    constexpr types::mutex& mtx(void)
+    {
+        return m_mtx;
+    }
 
-    bool empty(void) const;
+    /// @param lock should have already been locked
+    bool wait(types::mutex& lock);
     void notify(void);
-
-    void subscribe(thread* thd);
-    void unsubscribe(thread* thd);
+    void notify_all(void);
 };
 
 } // namespace kernel

+ 8 - 15
include/kernel/mem.h

@@ -3,8 +3,7 @@
 #include <stdint.h>
 #include <types/size.h>
 
-#define PAGE_SIZE (4096)
-#define KERNEL_IDENTICALLY_MAPPED_AREA_LIMIT ((void*)0x30000000)
+#define PAGE_SIZE (0x1000)
 
 #ifdef __cplusplus
 extern "C" {
@@ -89,25 +88,16 @@ typedef union pte_t {
 } pte_t;
 typedef pte_t (*pt_t)[1024];
 
-// in kernel_main.c
+// in mem.cpp
 extern uint8_t e820_mem_map[1024];
 extern uint32_t e820_mem_map_count;
 extern uint32_t e820_mem_map_entry_size;
-extern size_t kernel_size;
 extern struct mem_size_info mem_size_info;
 
-#define KERNEL_HEAP_START ((void*)0x30000000)
-#define KERNEL_HEAP_LIMIT ((void*)0x40000000)
+#define KERNEL_HEAP_START ((void*)0xd0000000)
+#define KERNEL_HEAP_LIMIT ((void*)0xd4000000)
 
-void* k_malloc(size_t size);
-
-void k_free(void* ptr);
-
-void* ki_malloc(size_t size);
-
-void ki_free(void* ptr);
-
-#define KERNEL_PAGE_DIRECTORY_ADDR ((pd_t)0x00001000)
+#define EARLY_KERNEL_PD_PAGE ((page_t)0x000001)
 
 void init_mem(void);
 
@@ -136,6 +126,9 @@ typedef struct segment_descriptor_struct {
     uint64_t base_high : 8;
 } segment_descriptor;
 
+// in mem.cpp
+extern segment_descriptor gdt[6];
+
 void create_segment_descriptor(
     segment_descriptor* sd,
     uint32_t base,

+ 133 - 117
include/kernel/mm.hpp

@@ -18,16 +18,18 @@
 
 constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
 
+constexpr uint32_t PAGE_COW = (1 << 0);
+constexpr uint32_t PAGE_MMAP = (1 << 1);
+#define PAGE_COW PAGE_COW
+#define PAGE_MMAP PAGE_MMAP
+
 struct page {
     page_t phys_page_id;
-    pte_t* pte;
     size_t* ref_count;
-    union {
-        uint32_t v;
-        struct {
-            uint32_t cow : 1;
-        } in;
-    } attr;
+    // 0 :11 : pte_index
+    // 12:31 : pt_page
+    uint32_t pg_pteidx;
+    uint32_t attr;
 };
 
 // private memory mapping
@@ -46,17 +48,6 @@ int mmap(
 
 using page_arr = types::vector<page, types::kernel_ident_allocator>;
 
-// allocate n raw page(s)
-// @return the id of the first page allocated
-page_t alloc_n_raw_pages(size_t n);
-void free_n_raw_pages(page_t start_pg, size_t n);
-
-pd_t alloc_pd(void);
-pt_t alloc_pt(void);
-
-void dealloc_pd(pd_t pd);
-void dealloc_pt(pt_t pt);
-
 // forward declaration
 namespace kernel {
 class mm_list;
@@ -86,6 +77,17 @@ inline constexpr uint32_t align_up(uint32_t v)
     return align_down<n>(v + pow<2, n>() - 1);
 }
 
+void dealloc_pd(page_t pd);
+
+// allocate a struct page together with the raw page
+page allocate_page(void);
+void free_page(page* pg);
+
+// TODO: this is for alloc_kstack()
+// CHANGE THIS
+page_t __alloc_raw_page(void);
+void __free_raw_page(page_t pg);
+
 struct mm {
 public:
     void* start;
@@ -108,9 +110,9 @@ public:
         return (char*)this->start + this->pgs->size() * PAGE_SIZE;
     }
 
-    inline bool is_ident(void) const
+    inline bool is_kernel_space(void) const
     {
-        return this->end() <= (void*)0x40000000U;
+        return this->start >= (void*)0xc0000000;
     }
 
     constexpr bool is_avail(void* start, void* end) const
@@ -121,11 +123,39 @@ public:
         return (start >= m_end || end <= m_start);
     }
 
-    int append_page(page* pg, bool present, bool write, bool priv, bool cow);
+    int append_page(page& pg, uint32_t attr, bool priv);
 };
 
 namespace kernel {
 
+uint8_t* pmap(page_t pg);
+void pfree(page_t pg);
+
+class paccess : public types::non_copyable {
+private:
+    page_t m_pg;
+    void* m_ptr;
+
+public:
+    paccess(void) = delete;
+    paccess(paccess&&) = delete;
+    paccess& operator=(paccess&&) = delete;
+
+    constexpr explicit paccess(page_t pg)
+        : m_pg(pg)
+    {
+        m_ptr = pmap(pg);
+    }
+    constexpr void* ptr(void) const
+    {
+        return m_ptr;
+    }
+    ~paccess()
+    {
+        pfree(m_pg);
+    }
+};
+
 class mm_list {
 public:
     using list_type = ::types::list<mm, types::kernel_ident_allocator>;
@@ -136,10 +166,10 @@ private:
     list_type m_areas;
 
 public:
-    pd_t m_pd;
+    page_t m_pd;
 
 public:
-    explicit constexpr mm_list(pd_t pd)
+    explicit constexpr mm_list(page_t pd)
         : m_pd(pd)
     {
     }
@@ -148,7 +178,9 @@ public:
         : m_areas(::types::move(v.m_areas))
         , m_pd(v.m_pd)
     {
-        v.m_pd = nullptr;
+        v.m_pd = 0;
+        for (auto& area : m_areas)
+            area.owner = this;
     }
     ~mm_list()
     {
@@ -203,7 +235,7 @@ public:
     constexpr void clear_user()
     {
         for (auto iter = this->begin(); iter != this->end();) {
-            if (iter->is_ident()) {
+            if (iter->is_kernel_space()) {
                 ++iter;
                 continue;
             }
@@ -218,17 +250,16 @@ public:
     {
         auto area = this->addarea(
             src.start, src.attr.in.write, src.attr.in.system);
+
         if (src.mapped_file) {
             area->mapped_file = src.mapped_file;
             area->file_offset = src.file_offset;
         }
 
         for (auto& pg : *src.pgs) {
-            if (area->append_page(&pg,
-                    true,
-                    src.attr.in.write,
-                    src.attr.in.system,
-                    true)
+            if (area->append_page(pg,
+                    PAGE_COW | (pg.attr & PAGE_MMAP),
+                    src.attr.in.system)
                 != GB_OK) {
                 return GB_FAILED;
             }
@@ -237,7 +268,7 @@ public:
         return GB_OK;
     }
 
-    constexpr void unmap(iterator_type area)
+    inline void unmap(iterator_type area)
     {
         int i = 0;
 
@@ -247,16 +278,13 @@ public:
         // bool should_invlpg = (area->pgs->size() > 4);
 
         for (auto& pg : *area->pgs) {
-            if (*pg.ref_count == 1) {
-                ki_free(pg.ref_count);
-                free_n_raw_pages(pg.phys_page_id, 1);
-            } else {
-                --*pg.ref_count;
-            }
+            kernel::paccess pa(pg.pg_pteidx >> 12);
+            auto pt = (pt_t)pa.ptr();
+            assert(pt);
+            auto* pte = *pt + (pg.pg_pteidx & 0xfff);
+            pte->v = 0;
 
-            pg.phys_page_id = 0;
-            pg.attr.v = 0;
-            pg.pte->v = 0;
+            free_page(&pg);
 
             invalidate_tlb((uint32_t)area->start + (i++) * PAGE_SIZE);
         }
@@ -295,88 +323,76 @@ inline kernel::mm_list* kernel_mms;
 inline page empty_page;
 // --------------------------------
 
-// translate physical address to virtual(mapped) address
-void* ptovp(pptr_t p_ptr);
-
 inline constexpr size_t vptrdiff(void* p1, void* p2)
 {
     return (uint8_t*)p1 - (uint8_t*)p2;
 }
-inline constexpr page* lto_page(mm* mm_area, void* l_ptr)
-{
-    size_t offset = vptrdiff(l_ptr, mm_area->start);
-    return &mm_area->pgs->at(offset / PAGE_SIZE);
-}
-inline constexpr page_t to_page(pptr_t ptr)
-{
-    return ptr >> 12;
-}
-inline constexpr size_t to_pdi(page_t pg)
-{
-    return pg >> 10;
-}
-inline constexpr size_t to_pti(page_t pg)
-{
-    return pg & (1024 - 1);
-}
-inline constexpr pptr_t to_pp(page_t p)
-{
-    return p << 12;
-}
-inline constexpr size_t lto_pdi(pptr_t ptr)
-{
-    return to_pdi(to_page(ptr));
-}
-inline constexpr size_t lto_pti(pptr_t ptr)
-{
-    return to_pti(to_page(ptr));
-}
-inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
-{
-    return *pt + to_pti(pg);
-}
-inline void* to_vp(page_t pg)
-{
-    return ptovp(to_pp(pg));
-}
-inline pd_t to_pd(page_t pg)
-{
-    return reinterpret_cast<pd_t>(to_vp(pg));
-}
-inline pt_t to_pt(page_t pg)
-{
-    return reinterpret_cast<pt_t>(to_vp(pg));
-}
-inline pt_t to_pt(pde_t* pde)
-{
-    return to_pt(pde->in.pt_page);
-}
-inline pde_t* to_pde(pd_t pd, void* addr)
-{
-    return *pd + lto_pdi((pptr_t)addr);
-}
-inline pte_t* to_pte(pt_t pt, void* addr)
-{
-    return *pt + lto_pti((pptr_t)addr);
-}
-inline pte_t* to_pte(pde_t* pde, void* addr)
-{
-    return to_pte(to_pt(pde), addr);
-}
-inline pte_t* to_pte(pd_t pd, void* addr)
-{
-    return to_pte(to_pde(pd, addr), addr);
-}
-inline pte_t* to_pte(pde_t* pde, page_t pg)
+// inline constexpr page* lto_page(mm* mm_area, void* l_ptr)
+// {
+//     size_t offset = vptrdiff(l_ptr, mm_area->start);
+//     return &mm_area->pgs->at(offset / PAGE_SIZE);
+// }
+// inline constexpr page_t to_page(pptr_t ptr)
+// {
+//     return ptr >> 12;
+// }
+// inline constexpr size_t to_pdi(page_t pg)
+// {
+//     return pg >> 10;
+// }
+// inline constexpr size_t to_pti(page_t pg)
+// {
+//     return pg & (1024 - 1);
+// }
+// inline constexpr pptr_t to_pp(page_t p)
+// {
+//     return p << 12;
+// }
+inline size_t v_to_pdi(void* addr)
 {
-    return to_pte(to_pt(pde), pg);
+    return (uint32_t)addr >> 22;
 }
-
-// allocate a raw page
-inline page_t alloc_raw_page(void)
+inline size_t v_to_pti(void* addr)
 {
-    return alloc_n_raw_pages(1);
+    return ((uint32_t)addr >> 12) & 0x3ff;
 }
-
-// allocate a struct page together with the raw page
-struct page allocate_page(void);
+// inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
+// {
+//     return *pt + to_pti(pg);
+// }
+// inline void* to_vp(page_t pg)
+// {
+//     return ptovp(to_pp(pg));
+// }
+// inline pd_t to_pd(page_t pg)
+// {
+//     return reinterpret_cast<pd_t>(to_vp(pg));
+// }
+// inline pt_t to_pt(page_t pg)
+// {
+//     return reinterpret_cast<pt_t>(to_vp(pg));
+// }
+// inline pt_t to_pt(pde_t* pde)
+// {
+//     return to_pt(pde->in.pt_page);
+// }
+// inline pde_t* to_pde(pd_t pd, void* addr)
+// {
+//     return *pd + lto_pdi((pptr_t)addr);
+// }
+// inline pte_t* to_pte(pt_t pt, void* addr)
+// {
+//     return *pt + lto_pti((pptr_t)addr);
+// }
+// inline pte_t* to_pte(pde_t* pde, void* addr)
+// {
+//     return to_pte(to_pt(pde), addr);
+// }
+// inline pte_t* to_pte(pd_t pd, void* addr)
+// {
+//     return to_pte(to_pde(pd, addr), addr);
+// }
+// inline pte_t* to_pte(pde_t* pde, page_t pg)
+// {
+//     return to_pte(to_pt(pde), pg);
+// }

+ 181 - 51
include/kernel/process.hpp

@@ -1,12 +1,16 @@
 #pragma once
 
+#include <fcntl.h>
 #include <kernel/errno.h>
 #include <kernel/event/evtqueue.hpp>
 #include <kernel/interrupt.h>
 #include <kernel/mm.hpp>
+#include <kernel/signal.hpp>
 #include <kernel/task.h>
+#include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
 #include <stdint.h>
+#include <sys/types.h>
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
 #include <types/hash_map.hpp>
@@ -14,10 +18,9 @@
 #include <types/map.hpp>
 #include <types/pair.hpp>
 #include <types/status.h>
+#include <types/string.hpp>
 #include <types/types.h>
 
-typedef size_t pid_t;
-
 class process;
 struct thread;
 
@@ -29,6 +32,8 @@ inline thread* volatile current_thread;
 inline proclist* procs;
 inline readyqueue* readythds;
 
+inline tss32_t tss;
+
 struct process_attr {
     uint16_t system : 1;
     uint16_t zombie : 1 = 0;
@@ -42,17 +47,12 @@ struct thread_attr {
 
 struct thread {
 private:
-    inline void alloc_kstack(void)
-    {
-        // TODO: alloc low mem
-        kstack = to_pp(alloc_n_raw_pages(2));
-        kstack += THREAD_KERNEL_STACK_SIZE;
-        esp = reinterpret_cast<uint32_t*>(kstack);
-    }
+    void alloc_kstack(void);
+    void free_kstack(uint32_t p);
 
 public:
     uint32_t* esp;
-    pptr_t kstack;
+    uint32_t pkstack;
     process* owner;
     thread_attr attr;
 
@@ -69,13 +69,13 @@ public:
 
     constexpr thread(thread&& val)
         : esp { val.esp }
-        , kstack { val.kstack }
+        , pkstack { val.pkstack }
         , owner { val.owner }
         , attr { val.attr }
     {
         val.attr = {};
         val.esp = 0;
-        val.kstack = 0;
+        val.pkstack = 0;
         val.owner = nullptr;
     }
 
@@ -94,8 +94,8 @@ public:
 
     constexpr ~thread()
     {
-        if (kstack)
-            free_n_raw_pages(to_page(kstack - THREAD_KERNEL_STACK_SIZE), 2);
+        if (pkstack)
+            free_kstack(pkstack);
     }
 };
 
@@ -120,9 +120,7 @@ public:
             thd.owner = new_parent;
     }
 
-    explicit constexpr thdlist(void)
-    {
-    }
+    explicit constexpr thdlist(void) = default;
 
     // implementation is below
     constexpr ~thdlist();
@@ -154,24 +152,45 @@ public:
     private:
         inline static container_type* files;
         array_type arr;
-        int next_fd = 0;
 
     public:
         inline static void init_global_file_container(void)
         {
-            files = types::pnew<types::kernel_allocator>(files);
+            files = new container_type;
         }
 
     private:
         // iter should not be nullptr
         constexpr void _close(container_type::iterator_type iter)
         {
-            if (iter->ref == 1)
+            if (iter->ref == 1) {
+                if (iter->type == fs::file::types::pipe) {
+                    assert(iter->flags.read | iter->flags.write);
+                    if (iter->flags.read)
+                        iter->ptr.pp->close_read();
+                    else
+                        iter->ptr.pp->close_write();
+
+                    if (iter->ptr.pp->is_free())
+                        delete iter->ptr.pp;
+                }
+
                 files->erase(iter);
-            else
+            } else
                 --iter->ref;
         }
 
+        constexpr int _next_fd(void) const
+        {
+            int fd = 0;
+
+            for (auto iter = arr.cbegin(); iter != arr.cend(); ++iter)
+                if (iter->key == fd)
+                    ++fd;
+
+            return fd;
+        }
+
     public:
         constexpr filearr(const filearr&) = delete;
         constexpr filearr& operator=(const filearr&) = delete;
@@ -179,18 +198,32 @@ public:
         constexpr filearr(void) = default;
         constexpr filearr(filearr&& val)
             : arr { types::move(val.arr) }
-            , next_fd { val.next_fd }
         {
-            val.next_fd = 0;
         }
 
-        constexpr void dup(const filearr& orig)
+        constexpr int dup(int old_fd)
         {
-            if (this->next_fd)
-                return;
+            return dup2(old_fd, _next_fd());
+        }
 
-            this->next_fd = orig.next_fd;
+        // TODO: the third parameter should be int flags
+        //       determining whether the fd should be closed
+        //       after exec() (FD_CLOEXEC)
+        constexpr int dup2(int old_fd, int new_fd)
+        {
+            close(new_fd);
+
+            auto iter = arr.find(old_fd);
+            if (!iter)
+                return -EBADF;
 
+            this->arr.insert(types::make_pair(new_fd, iter->value));
+            ++iter->value->ref;
+            return new_fd;
+        }
+
+        constexpr void dup_all(const filearr& orig)
+        {
             for (auto iter : orig.arr) {
                 this->arr.insert(types::make_pair(iter.key, iter.value));
                 ++iter.value->ref;
@@ -206,8 +239,50 @@ public:
                 return &iter->value;
         }
 
-        // TODO: file opening flags (permissions etc.)
-        int open(const char* filename, uint32_t)
+        int pipe(int pipefd[2])
+        {
+            // TODO: set read/write flags
+            auto* pipe = new fs::pipe;
+
+            auto iter = files->emplace_back(fs::file {
+                fs::file::types::pipe,
+                { .pp = pipe },
+                nullptr,
+                0,
+                1,
+                {
+                    .read = 1,
+                    .write = 0,
+                },
+            });
+            int fd = _next_fd();
+            arr.insert(types::make_pair(fd, iter));
+
+            // TODO: use copy_to_user()
+            pipefd[0] = fd;
+
+            iter = files->emplace_back(fs::file {
+                fs::file::types::pipe,
+                { .pp = pipe },
+                nullptr,
+                0,
+                1,
+                {
+                    .read = 0,
+                    .write = 1,
+                },
+            });
+            fd = _next_fd();
+            arr.insert(types::make_pair(fd, iter));
+
+            // TODO: use copy_to_user()
+            pipefd[1] = fd;
+
+            return 0;
+        }
+
+        // TODO: file opening permissions check
+        int open(const char* filename, uint32_t flags)
         {
             auto* dentry = fs::vfs_open(filename);
 
@@ -216,27 +291,25 @@ public:
                 return -1;
             }
 
-            // TODO: check whether dentry is a file if O_DIRECTORY is set
-            // if (!(dentry->ind->flags.in.file || dentry->ind->flags.in.special_node)) {
-            //     errno = EISDIR;
-            //     return -1;
-            // }
-
-            // TODO: unify file, inode, dentry TYPE
-            fs::file::types type = fs::file::types::regular_file;
-            if (dentry->ind->flags.in.directory)
-                type = fs::file::types::directory;
-            if (dentry->ind->flags.in.special_node)
-                type = fs::file::types::block_dev;
+            // check whether dentry is a file if O_DIRECTORY is set
+            if ((flags & O_DIRECTORY) && !dentry->ind->flags.in.directory) {
+                errno = ENOTDIR;
+                return -1;
+            }
 
             auto iter = files->emplace_back(fs::file {
-                type,
-                dentry->ind,
+                fs::file::types::ind,
+                { .ind = dentry->ind },
                 dentry->parent,
                 0,
-                1 });
-
-            int fd = next_fd++;
+                1,
+                {
+                    .read = !!(flags & (O_RDONLY | O_RDWR)),
+                    .write = !!(flags & (O_WRONLY | O_RDWR)),
+                },
+            });
+
+            int fd = _next_fd();
             arr.insert(types::make_pair(fd, iter));
             return fd;
         }
@@ -262,20 +335,36 @@ public:
         }
     };
 
+    struct wait_obj {
+        pid_t pid;
+        int code;
+    };
+
 public:
     mutable kernel::mm_list mms;
     thdlist thds;
-    kernel::evtqueue wait_lst;
+    kernel::cond_var cv_wait;
+    types::list<wait_obj> waitlist;
     process_attr attr;
+    filearr files;
+    types::string<> pwd;
+    kernel::signal_list signals;
+
     pid_t pid;
     pid_t ppid;
-    filearr files;
+    pid_t pgid;
+    pid_t sid;
 
 public:
+    // if waitlist is not empty or mutex in cv_wait
+    // is locked, its behavior is undefined
     process(process&& val);
     process(const process&);
 
-    explicit process(pid_t ppid, bool system = true);
+    explicit process(pid_t ppid,
+        bool system = true,
+        types::string<>&& path = "/",
+        kernel::signal_list&& sigs = {});
 
     constexpr bool is_system(void) const
     {
@@ -299,12 +388,14 @@ class proclist final {
 public:
     using list_type = types::map<pid_t, process>;
     using child_index_type = types::hash_map<pid_t, types::list<pid_t>, types::linux_hasher<pid_t>>;
+    using tty_index_type = types::map<pid_t, tty*>;
     using iterator_type = list_type::iterator_type;
     using const_iterator_type = list_type::const_iterator_type;
 
 private:
     list_type m_procs;
     child_index_type m_child_idx;
+    tty_index_type m_tty_idx;
 
 public:
     template <typename... Args>
@@ -326,6 +417,25 @@ public:
         return iter;
     }
 
+    constexpr void set_ctrl_tty(pid_t pid, tty* _tty)
+    {
+        auto iter = m_tty_idx.find(pid);
+        _tty->set_pgrp(pid);
+        if (iter) {
+            iter->value = _tty;
+        } else {
+            m_tty_idx.insert(types::make_pair(pid, _tty));
+        }
+    }
+
+    constexpr tty* get_ctrl_tty(pid_t pid)
+    {
+        auto iter = m_tty_idx.find(pid);
+        if (!iter)
+            return nullptr;
+        return iter->value;
+    }
+
     constexpr void remove(pid_t pid)
     {
         make_children_orphans(pid);
@@ -343,7 +453,10 @@ public:
 
     constexpr process* find(pid_t pid)
     {
-        return &m_procs.find(pid)->value;
+        auto iter = m_procs.find(pid);
+        // TODO: change this
+        assert(!!iter);
+        return &iter->value;
     }
 
     constexpr bool has_child(pid_t pid)
@@ -365,6 +478,20 @@ public:
         }
     }
 
+    void send_signal(pid_t pid, kernel::sig_t signal)
+    {
+        auto iter = this->find(pid);
+        if (!iter)
+            return iter->signals.set(signal);
+    }
+    void send_signal_grp(pid_t pgid, kernel::sig_t signal)
+    {
+        for (auto& proc : m_procs) {
+            if (proc.value.pgid == pgid)
+                proc.value.signals.set(signal);
+        }
+    }
+
     void kill(pid_t pid, int exit_code);
 };
 
@@ -421,7 +548,8 @@ public:
 };
 
 void NORETURN init_scheduler(void);
-void schedule(void);
+/// @return true if returned normally, false if being interrupted
+bool schedule(void);
 void NORETURN schedule_noreturn(void);
 
 constexpr uint32_t push_stack(uint32_t** stack, uint32_t val)
@@ -442,3 +570,5 @@ void k_new_thread(void (*func)(void*), void* data);
 
 void NORETURN freeze(void);
 void NORETURN kill_current(int exit_code);
+
+void check_signal(void);

+ 70 - 0
include/kernel/signal.hpp

@@ -0,0 +1,70 @@
+#pragma once
+
+#include <stdint.h>
+#include <types/cplusplus.hpp>
+#include <types/list.hpp>
+
+namespace kernel {
+
+using sig_t = uint32_t;
+
+constexpr sig_t SIGINT = 1 << 0;
+constexpr sig_t SIGQUIT = 1 << 1;
+constexpr sig_t SIGSTOP = 1 << 2;
+constexpr sig_t SIGPIPE = 1 << 3;
+
+class signal_list {
+public:
+    using list_type = types::list<sig_t>;
+
+private:
+    list_type m_list;
+    sig_t m_mask;
+
+public:
+    constexpr signal_list(void)
+        : m_mask(0)
+    {
+    }
+    constexpr signal_list(const signal_list& val)
+        : m_list(val.m_list)
+        , m_mask(val.m_mask)
+    {
+    }
+
+    constexpr signal_list(signal_list&& val)
+        : m_list(types::move(val.m_list))
+        , m_mask(val.m_mask)
+    {
+    }
+
+    constexpr bool empty(void) const
+    {
+        return this->m_list.empty();
+    }
+
+    constexpr void set(sig_t signal)
+    {
+        if (this->m_mask && signal)
+            return;
+
+        this->m_list.push_back(signal);
+        this->m_mask |= signal;
+    }
+
+    constexpr sig_t pop(void)
+    {
+        if (this->empty())
+            return 0;
+
+        auto iter = this->m_list.begin();
+        sig_t signal = *iter;
+        this->m_list.erase(iter);
+
+        this->m_mask &= ~signal;
+
+        return signal;
+    }
+};
+
+} // namespace kernel

+ 1 - 1
include/kernel/syscall.hpp

@@ -4,6 +4,6 @@
 #include <types/types.h>
 
 // return value is stored in %eax and %edx
-typedef void (*syscall_handler)(interrupt_stack* data);
+typedef int (*syscall_handler)(interrupt_stack* data);
 
 void init_syscall(void);

+ 14 - 1
include/kernel/tty.hpp

@@ -1,6 +1,7 @@
 #pragma once
 #include <kernel/event/evtqueue.hpp>
 #include <stdint.h>
+#include <sys/types.h>
 #include <types/allocator.hpp>
 #include <types/buffer.hpp>
 #include <types/cplusplus.hpp>
@@ -17,12 +18,24 @@ public:
     void print(const char* str);
     size_t read(char* buf, size_t buf_size, size_t n);
 
+    constexpr void set_pgrp(pid_t pgid)
+    {
+        fg_pgroup = pgid;
+    }
+
+    constexpr pid_t get_pgrp(void) const
+    {
+        return fg_pgroup;
+    }
+
     char name[NAME_SIZE];
     bool echo = true;
 
 protected:
     types::buffer<types::kernel_ident_allocator> buf;
-    kernel::evtqueue blocklist;
+    kernel::cond_var m_cv;
+
+    pid_t fg_pgroup;
 };
 
 class vga_tty : public virtual tty {

+ 52 - 5
include/kernel/vfs.hpp

@@ -1,10 +1,15 @@
 #pragma once
 
+#include <assert.h>
+#include <kernel/event/evtqueue.hpp>
 #include <stdint.h>
 #include <types/allocator.hpp>
+#include <types/buffer.hpp>
+#include <types/cplusplus.hpp>
 #include <types/function.hpp>
 #include <types/hash_map.hpp>
 #include <types/list.hpp>
+#include <types/lock.hpp>
 #include <types/map.hpp>
 #include <types/types.h>
 #include <types/vector.hpp>
@@ -193,17 +198,59 @@ public:
     virtual int inode_readdir(inode* dir, size_t offset, filldir_func callback) = 0;
 };
 
+class pipe : public types::non_copyable {
+private:
+    static constexpr size_t PIPE_SIZE = 4096;
+    static constexpr uint32_t READABLE = 1;
+    static constexpr uint32_t WRITABLE = 2;
+
+private:
+    types::buffer<types::kernel_allocator> buf;
+    kernel::cond_var m_cv;
+    uint32_t flags;
+
+public:
+    pipe(void);
+
+    void close_read(void);
+    void close_write(void);
+
+    int write(const char* buf, size_t n);
+    int read(char* buf, size_t n);
+
+    constexpr bool is_readable(void) const
+    {
+        return flags & READABLE;
+    }
+
+    constexpr bool is_writeable(void) const
+    {
+        return flags & WRITABLE;
+    }
+
+    constexpr bool is_free(void) const
+    {
+        return !(flags & (READABLE | WRITABLE));
+    }
+};
+
 struct file {
     enum class types {
-        regular_file,
-        directory,
-        block_dev,
-        char_dev,
+        ind,
+        pipe,
+        socket,
     } type;
-    inode* ind;
+    union {
+        inode* ind;
+        pipe* pp;
+    } ptr;
     vfs::dentry* parent;
     size_t cursor;
     size_t ref;
+    struct file_flags {
+        uint32_t read : 1;
+        uint32_t write : 1;
+    } flags;
 };
 
 inline fs::vfs::dentry* fs_root;

+ 0 - 10
include/kernel_main.hpp

@@ -1,10 +0,0 @@
-#pragma once
-#include <types/types.h>
-
-#define KERNEL_STACK_SIZE (16 * 1024)
-#define KERNEL_STACK_SEGMENT (0x10)
-
-#define KERNEL_START_ADDR (0x00100000)
-
-// in kernel_main.cpp
-extern struct tss32_t tss;

+ 186 - 18
include/types/allocator.hpp

@@ -1,5 +1,5 @@
 #pragma once
-#include <kernel/mem.h>
+#include <assert.h>
 #include <stdint.h>
 #include <types/cplusplus.hpp>
 #include <types/types.h>
@@ -11,6 +11,160 @@ constexpr void* operator new(size_t, void* ptr)
 
 namespace types {
 
+namespace __allocator {
+    class brk_memory_allocator {
+    public:
+        using byte = uint8_t;
+        using size_type = size_t;
+
+        struct mem_blk_flags {
+            uint8_t is_free;
+            uint8_t has_next;
+            uint8_t _unused2;
+            uint8_t _unused3;
+        };
+
+        struct mem_blk {
+            size_t size;
+            struct mem_blk_flags flags;
+            // the first byte of the memory space
+            // the minimal allocated space is 4 bytes
+            uint8_t data[4];
+        };
+
+    private:
+        byte* p_start;
+        byte* p_break;
+        byte* p_limit;
+
+        brk_memory_allocator(void) = delete;
+        brk_memory_allocator(const brk_memory_allocator&) = delete;
+        brk_memory_allocator(brk_memory_allocator&&) = delete;
+
+        constexpr int brk(byte* addr)
+        {
+            if (unlikely(addr >= p_limit))
+                return GB_FAILED;
+            p_break = addr;
+            return GB_OK;
+        }
+
+        // sets errno
+        inline byte* sbrk(size_type increment)
+        {
+            if (unlikely(brk(p_break + increment) != GB_OK))
+                return nullptr;
+            else
+                return p_break;
+        }
+
+        inline mem_blk* _find_next_mem_blk(mem_blk* blk, size_type blk_size)
+        {
+            byte* p = (byte*)blk;
+            p += sizeof(mem_blk);
+            p += blk_size;
+            p -= (4 * sizeof(byte));
+            return (mem_blk*)p;
+        }
+
+        // sets errno
+        // @param start_pos position where to start finding
+        // @param size the size of the block we're looking for
+        // @return found block if suitable block exists, if not, the last block
+        inline mem_blk* find_blk(mem_blk* start_pos, size_type size)
+        {
+            while (1) {
+                if (start_pos->flags.is_free && start_pos->size >= size) {
+                    return start_pos;
+                } else {
+                    if (unlikely(!start_pos->flags.has_next))
+                        return start_pos;
+
+                    start_pos = _find_next_mem_blk(start_pos, start_pos->size);
+                }
+            }
+        }
+
+        inline mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
+        {
+            auto ret = sbrk(sizeof(mem_blk) + size - 4 * sizeof(byte));
+            if (!ret)
+                return nullptr;
+
+            mem_blk* blk = _find_next_mem_blk(blk_before, blk_before->size);
+
+            blk_before->flags.has_next = 1;
+
+            blk->flags.has_next = 0;
+            blk->flags.is_free = 1;
+            blk->size = size;
+
+            return blk;
+        }
+
+        inline void split_block(mem_blk* blk, size_type this_size)
+        {
+            // block is too small to get split
+            if (blk->size < sizeof(mem_blk) + this_size) {
+                return;
+            }
+
+            mem_blk* blk_next = _find_next_mem_blk(blk, this_size);
+
+            blk_next->size = blk->size
+                - this_size
+                - sizeof(mem_blk)
+                + 4 * sizeof(byte);
+
+            blk_next->flags.has_next = blk->flags.has_next;
+            blk_next->flags.is_free = 1;
+
+            blk->flags.has_next = 1;
+            blk->size = this_size;
+        }
+
+    public:
+        inline brk_memory_allocator(byte* start, size_type limit)
+            : p_start(start)
+            , p_limit(p_start + limit)
+        {
+            brk(p_start);
+            mem_blk* p_blk = (mem_blk*)sbrk(0);
+            p_blk->size = 4;
+            p_blk->flags.has_next = 0;
+            p_blk->flags.is_free = 1;
+        }
+
+        // sets errno
+        inline void* alloc(size_type size)
+        {
+            struct mem_blk* block_allocated;
+
+            block_allocated = find_blk((mem_blk*)p_start, size);
+            if (!block_allocated->flags.has_next
+                && (!block_allocated->flags.is_free || block_allocated->size < size)) {
+                // 'block_allocated' in the argument list is the pointer
+                // pointing to the last block
+                block_allocated = allocate_new_block(block_allocated, size);
+                if (!block_allocated)
+                    return nullptr;
+            } else {
+                split_block(block_allocated, size);
+            }
+
+            block_allocated->flags.is_free = 0;
+            return block_allocated->data;
+        }
+
+        inline void free(void* ptr)
+        {
+            mem_blk* blk = (mem_blk*)((byte*)ptr - (sizeof(mem_blk_flags) + sizeof(size_t)));
+            blk->flags.is_free = 1;
+            // TODO: fusion free blocks nearby
+        }
+    };
+}; // namespace __allocator
+
 template <typename T>
 concept Allocator = requires(size_t size, typename T::value_type* ptr)
 {
@@ -26,21 +180,11 @@ concept Allocator = requires(size_t size, typename T::value_type* ptr)
 template <Allocator T>
 class allocator_traits;
 
-template <typename T>
-class kernel_allocator {
-public:
-    using value_type = T;
-
-    static constexpr value_type* allocate_memory(size_t count)
-    {
-        return static_cast<value_type*>(::k_malloc(count));
-    }
-
-    static constexpr void deallocate_memory(value_type* ptr)
-    {
-        ::k_free(ptr);
-    }
-};
+namespace __allocator {
+    inline char __ident_heap[0x100000];
+    inline __allocator::brk_memory_allocator
+        m_alloc { (uint8_t*)__ident_heap, sizeof(__ident_heap) };
+} // namespace __allocator
 
 template <typename T>
 class kernel_ident_allocator {
@@ -49,12 +193,12 @@ public:
 
     static constexpr value_type* allocate_memory(size_t count)
     {
-        return static_cast<value_type*>(::ki_malloc(count));
+        return static_cast<value_type*>(__allocator::m_alloc.alloc(count));
     }
 
     static constexpr void deallocate_memory(value_type* ptr)
     {
-        ::ki_free(ptr);
+        __allocator::m_alloc.free(ptr);
     }
 };
 
@@ -125,4 +269,28 @@ public:
         deallocate(ptr);
     }
 };
+
+namespace __allocator {
+    inline __allocator::brk_memory_allocator* m_palloc;
+    inline void init_kernel_heap(void* start, size_t sz)
+    {
+        m_palloc = pnew<kernel_ident_allocator>(m_palloc, (uint8_t*)start, sz);
+    }
+} // namespace __allocator
+
+template <typename T>
+class kernel_allocator {
+public:
+    using value_type = T;
+
+    static constexpr value_type* allocate_memory(size_t count)
+    {
+        return static_cast<value_type*>(__allocator::m_palloc->alloc(count));
+    }
+
+    static constexpr void deallocate_memory(value_type* ptr)
+    {
+        __allocator::m_palloc->free(ptr);
+    }
+};
 } // namespace types

+ 3 - 3
include/types/bitmap.h

@@ -6,9 +6,9 @@
 extern "C" {
 #endif
 
-int bm_test(char* bm, size_t n);
-void bm_set(char* bm, size_t n);
-void bm_clear(char* bm, size_t n);
+int bm_test(uint8_t* bm, size_t n);
+void bm_set(uint8_t* bm, size_t n);
+void bm_clear(uint8_t* bm, size_t n);
 
 #ifdef __cplusplus
 }

+ 10 - 0
include/types/buffer.hpp

@@ -134,6 +134,16 @@ public:
         head = _forward(head);
         return c;
     }
+
+    constexpr size_t size(void) const
+    {
+        return count;
+    }
+
+    constexpr size_t avail(void) const
+    {
+        return end - start + 1 - count;
+    }
 };
 
 } // namespace types

+ 27 - 1
include/types/elf.hpp

@@ -14,7 +14,7 @@ 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_addr_t ELF_STACK_BOTTOM = 0xbffff000;
 constexpr elf32_off_t ELF_STACK_SIZE = 8 * 1024 * 1024;
 constexpr elf32_addr_t ELF_STACK_TOP = ELF_STACK_BOTTOM - ELF_STACK_SIZE;
 
@@ -109,6 +109,32 @@ struct PACKED elf32_program_header_entry {
     uint32_t align;
 };
 
+struct PACKED elf32_section_header_entry {
+    elf32_off_t sh_name;
+    enum : uint32_t {
+        SHT_NULL = 0x00,
+        SHT_PROGBITS = 0x01,
+        SHT_RELA = 0x04,
+        SHT_DYNAMIC = 0x06,
+        SHT_NOTE = 0x07,
+        SHT_NOBITS = 0x08,
+        SHT_REL = 0x09,
+        SHT_DYNSYM = 0x0b,
+        SHT_INIT_ARRAY = 0x0e,
+        SHT_FINI_ARRAY = 0x0f,
+        SHT_PREINIT_ARRAY = 0x0f,
+    } sh_type;
+    enum : uint32_t {
+        SHF_WRITE = 0x01,
+        SHF_ALLOC = 0x02,
+        SHF_EXECINSTR = 0x04,
+    } sh_flags;
+    elf32_addr_t sh_addr;
+    elf32_off_t sh_offset;
+    uint32_t sh_size;
+    char _[16];
+};
+
 struct elf32_load_data {
     const char* exec;
     const char* const* argv;

+ 6 - 2
include/types/list.hpp

@@ -313,7 +313,9 @@ public:
 
     constexpr iterator_type begin() noexcept
     {
-        return iterator_type(head->next);
+        if (head)
+            return iterator_type(head->next);
+        return end();
     }
 
     constexpr iterator_type end() noexcept
@@ -323,7 +325,9 @@ public:
 
     constexpr const_iterator_type begin() const noexcept
     {
-        return const_iterator_type(head->next);
+        if (head)
+            return const_iterator_type(head->next);
+        return end();
     }
 
     constexpr const_iterator_type end() const noexcept

+ 65 - 52
include/types/map.hpp

@@ -220,60 +220,74 @@ public:
                 second = tmp;
             }
 
-            node* p = first->parent;
-            node* cl = first->left;
-            node* cr = first->right;
-
-            bool is_first_left = first->is_left_child();
-            bool is_second_left = second->is_left_child();
-
-            if (!first->is_root()) {
-                if (is_first_left)
-                    p->left = second;
-                else
-                    p->right = second;
-            }
-
-            first->left = second->left;
-            first->right = second->right;
-            if (first->left)
-                first->left->parent = first;
-            if (first->right)
-                first->right->parent = first;
+            bool f_is_left_child = first->parent ? first->is_left_child() : false;
+            bool s_is_left_child = second->parent ? second->is_left_child() : false;
+
+            node* fp = first->parent;
+            node* fl = first->left;
+            node* fr = first->right;
+
+            node* sp = second->parent;
+            node* sl = second->left;
+            node* sr = second->right;
+
+            if (second->parent != first) {
+                first->parent = sp;
+                if (sp) {
+                    if (s_is_left_child)
+                        sp->left = first;
+                    else
+                        sp->right = first;
+                }
+                first->left = sl;
+                if (sl)
+                    sl->parent = first;
+                first->right = sr;
+                if (sr)
+                    sr->parent = first;
+
+                second->parent = fp;
+                if (fp) {
+                    if (f_is_left_child)
+                        fp->left = second;
+                    else
+                        fp->right = second;
+                }
 
-            if (second->parent == first) {
+                second->left = fl;
+                if (fl)
+                    fl->parent = second;
+                second->right = fr;
+                if (fr)
+                    fr->parent = second;
+            } else {
+                first->left = sl;
+                if (sl)
+                    sl->parent = first;
+                first->right = sr;
+                if (sr)
+                    sr->parent = first;
+
+                second->parent = fp;
+                if (fp) {
+                    if (f_is_left_child)
+                        fp->left = second;
+                    else
+                        fp->right = second;
+                }
                 first->parent = second;
-                second->parent = p;
 
-                if (is_second_left) {
-                    if (cr)
-                        cr->parent = second;
+                if (s_is_left_child) {
                     second->left = first;
-                    second->right = cr;
+                    second->right = fr;
+                    if (fr)
+                        fr->parent = second;
                 } else {
-                    if (cl)
-                        cl->parent = second;
                     second->right = first;
-                    second->left = cl;
-                }
-            } else {
-                first->parent = second->parent;
-
-                if (cl)
-                    cl->parent = second;
-                if (cr)
-                    cr->parent = second;
-                second->left = cl;
-                second->right = cr;
-
-                if (!second->is_root()) {
-                    if (is_second_left)
-                        second->parent->left = first;
-                    else
-                        second->parent->right = first;
+                    second->left = fl;
+                    if (fl)
+                        fl->parent = second;
                 }
-
-                second->parent = p;
             }
         }
     };
@@ -282,12 +296,9 @@ public:
 
     template <bool Const>
     class iterator {
-    private:
-        static constexpr bool _is_const_iterator = Const;
-
     public:
-        using node_pointer_type = typename traits::condition<_is_const_iterator, const node*, node*>::type;
-        using value_type = typename traits::condition<_is_const_iterator, const pair_type, pair_type>::type;
+        using node_pointer_type = typename traits::condition<Const, const node*, node*>::type;
+        using value_type = typename traits::condition<Const, const pair_type, pair_type>::type;
         using pointer_type = typename traits::add_pointer<value_type>::type;
         using reference_type = typename traits::add_reference<value_type>::type;
 
@@ -323,12 +334,14 @@ public:
         constexpr iterator& operator=(const iterator& iter)
         {
             p = iter.p;
+            return *this;
         }
 
         constexpr iterator& operator=(iterator&& iter)
         {
             p = iter.p;
             iter.p = nullptr;
+            return *this;
         }
 
         constexpr bool operator==(const iterator& iter) const

+ 1 - 1
include/types/size.h

@@ -19,4 +19,4 @@ typedef int64_t diff_t;
 #endif
 
 typedef ptr_t pptr_t;
-typedef size_t page_t;
+typedef ssize_t page_t;

+ 1 - 0
include/types/vector.hpp

@@ -173,6 +173,7 @@ public:
     constexpr void resize(size_type n)
     {
         value_type* new_ptr = allocator_traits<allocator_type>::allocate(n);
+        assert(!n || (n && new_ptr));
 
         m_capacity = n;
         size_t orig_size = m_size;

+ 147 - 10
pretty-print.py

@@ -1,4 +1,5 @@
 import gdb.printing
+import re
 
 def create_iter(item, end, idx):
     return vectorPrinter._iterator(item, end, idx)
@@ -35,12 +36,78 @@ class vectorPrinter:
     def children(self):
         return self._iterator(self.val['m_arr'], self.val['m_arr'] + self.val['m_size'], 0)
 
+def _leftmost(node):
+    ret = node
+    while ret['left'] != 0:
+        ret = ret['left'].dereference()
+    return ret
+
+def _next(node):
+    if node['right']:
+        return _leftmost(node['right'].dereference())
+    else:
+        if node['parent'] == 0:
+            return None
+        parent = node['parent'].dereference()
+        if parent['left'] == node.address:
+            return parent
+        ret = node
+        while True:
+            ret = ret['parent'].dereference()
+            if ret['parent'] == 0:
+                return None
+            if ret['parent'].dereference()['left'] == ret.address:
+                break
+        return ret['parent'].dereference()
+
+class mapPrinter:
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return "types::map"
+
+    def display_hint(self):
+        return 'array'
+
+    def children(self):
+        yield '[root]', self.val['root']
+        if self.val['root'] == 0:
+            return
+
+        nd = _leftmost(self.val['root'].dereference())
+        i = 0
+        while True:
+            yield "[%d]" % i, nd['v']
+            nd = _next(nd)
+            i += 1
+            if nd == None:
+                break
+
 class stringPrinter:
     def __init__(self, val):
         self.val = val
     
     def to_string(self):
         return self.val['m_arr']
+    
+    def children(self):
+        yield 'str', self.val['m_arr']
+
+        if self.val['m_arr'] == 0:
+            return
+
+        yield 'length', self.val['m_size'] - 1
+
+        ptr = self.val['m_arr']
+        i = 0
+
+        while ptr.dereference() != 0:
+            yield '[%d]' % i, ptr.dereference()
+            ptr += 1
+            i += 1
+
+        yield '[%d]' % i, 0
 
 class listPrinter:
     def __init__(self, val):
@@ -53,21 +120,91 @@ class listPrinter:
         return 'array'
 
     def children(self):
-        node = self.val['head']['next']
+        head = self.val['head']
         end = self.val['tail']
+
+        yield '[head]', head
+        yield '[tail]', end
+        
+        if head == 0 or end == 0:
+            return
+
+        node = head['next']
         idx = 0
         while node != end:
             yield '[%d]' % idx, node['value']
             idx += 1
             node = node['next']
 
-def build_pretty_printer():
-    pp = gdb.printing.RegexpCollectionPrettyPrinter("gbos")
-    pp.add_printer("vector", "^types::vector<.*?>$", vectorPrinter)
-    pp.add_printer("string", "^types::string<.*?>$", stringPrinter)
-    pp.add_printer("list", "^types::list<.*?>$", listPrinter)
-    return pp
+class listIteratorPrinter:
+    def __init__(self, val):
+        self.val = val
+    
+    def children(self):
+        yield '[addr]', self.val['n']
+        if self.val['n'] == 0:
+            return
+
+        for field in self.val['n']['value'].type.fields():
+            yield field.name, self.val['n']['value'][field.name]
+
+class mapIteratorPrinter:
+    def __init__(self, val):
+        self.val = val
+    
+    def children(self):
+        yield '[addr]', self.val['p']
+        if self.val['p'] == 0:
+            return
+        
+        yield '[key]', self.val['p']['v']['key']
+        yield '[value]', self.val['p']['v']['value']
+
+class vectorIteratorPrinter:
+    def __init__(self, val):
+        self.val = val
+    
+    def children(self):
+        yield 'value', self.val['p'].dereference()
+
+def build_pretty_printer(val):
+    type = val.type
+
+    if type.code == gdb.TYPE_CODE_REF:
+        type = type.target()
+    if type.code == gdb.TYPE_CODE_PTR:
+        type = type.target()
+    
+    type = type.unqualified().strip_typedefs()
+    typename = type.tag
+
+    if typename == None:
+        return None
+
+    if re.compile(r"^types::list<.*?>::node<.*?>$").match(typename):
+        return None
+
+    if re.compile(r"^types::map<.*?,.*?,.*?>::iterator<.*?>$").match(typename):
+        return mapIteratorPrinter(val)
+    
+    if re.compile(r"^types::list<.*?>::iterator<.*?>$").match(typename):
+        return listIteratorPrinter(val)
+
+    if re.compile(r"^types::vector<.*?>::iterator<.*?>$").match(typename):
+        return vectorIteratorPrinter(val)
+
+    if re.compile(r"^types::list<.*?>$").match(typename):
+        return listPrinter(val)
+
+    if re.compile(r"^types::vector<.*?>$").match(typename):
+        return vectorPrinter(val)
+
+    if re.compile(r"^types::string<.*?>$").match(typename):
+        return stringPrinter(val)
+
+    if re.compile(r"^types::map<.*?>$").match(typename):
+        return mapPrinter(val)
+    
+    return None
 
-gdb.printing.register_pretty_printer(
-        gdb.current_objfile(),
-        build_pretty_printer())
+gdb.pretty_printers.append(build_pretty_printer)

+ 0 - 30
src/asm/a20.s

@@ -1,30 +0,0 @@
-.text
-
-.globl check_a20_on
-.type  check_a20_on @function
-
-check_a20_on:
-    pushal
-    movl $0x112345, %edi
-    movl $0x012345, %esi
-
-    movl (%esi), %eax
-    movl (%edi), %ecx
-
-    movl %esi, (%esi)
-    movl %edi, (%edi)
-    cmpsl
-
-    subl $4, %esi
-    subl $4, %edi
-
-    movl %eax, (%esi)
-    movl %ecx, (%edi)
-
-    popal
-    jne a20_on
-    movl $0, %eax
-    ret
-a20_on:
-    movl $1, %eax
-    ret

+ 15 - 19
src/asm/interrupt.s

@@ -182,35 +182,18 @@ irq15:
     popal
     iret
 
-.globl asm_load_idt
-.type  asm_load_idt @function
-asm_load_idt:
-    movl 4(%esp), %edx
-    lidt (%edx)
-    movl 8(%esp), %edx
-    cmpl $0, %edx
-    je asm_load_idt_skip
-    sti
-asm_load_idt_skip:
-    ret
-
 .globl syscall_stub
 .type  syscall_stub @function
 syscall_stub:
-    cmpl $16, %eax
-    jge syscall_stub_end
     pushal
 
-    # syscall function no. is in %eax
-    # store it in %ebx
-    movl %eax, %ebx
     # stack alignment and push *data
     movl %esp, %eax
     subl $0x4, %esp
     andl $0xfffffff0, %esp
     movl %eax, (%esp)
 
-    call *syscall_handlers(,%ebx,4)
+    call syscall_entry
 
     # restore stack
     popl %esp
@@ -219,7 +202,6 @@ syscall_stub:
 .type  _syscall_stub_fork_return @function
 _syscall_stub_fork_return:
     popal
-syscall_stub_end:
     iret
 
 # parameters
@@ -251,3 +233,17 @@ asm_ctx_switch:
 
 _ctx_switch_return:
     ret
+
+.section .text.kinit
+
+.globl asm_load_idt
+.type  asm_load_idt @function
+asm_load_idt:
+    movl 4(%esp), %edx
+    lidt (%edx)
+    movl 8(%esp), %edx
+    cmpl $0, %edx
+    je asm_load_idt_skip
+    sti
+asm_load_idt_skip:
+    ret

+ 1 - 0
src/asm/port_io.s

@@ -41,6 +41,7 @@ asm_sti:
     sti
     ret
 
+.section .text.kinit
 .globl asm_enable_sse
 .type  asm_enable_sse @function
 asm_enable_sse:

+ 9 - 6
src/asm/sys.s

@@ -6,9 +6,18 @@
 .type   asm_switch_pd @function
 asm_switch_pd:
     movl 4(%esp), %eax
+    shll $12, %eax
     movl %eax, %cr3
     ret
 
+.global current_pd
+.type   current_pd @function
+current_pd:
+    movl %cr3, %eax
+    ret
+
+.section .text.kinit
+
 .global asm_enable_paging
 .type   asm_enable_paging @function
 asm_enable_paging:
@@ -24,12 +33,6 @@ asm_enable_paging:
 
     ret
 
-.global current_pd
-.type   current_pd @function
-current_pd:
-    movl %cr3, %eax
-    ret
-
 .global asm_load_gdt
 .type   asm_load_gdt @function
 asm_load_gdt:

+ 120 - 89
src/boot.s

@@ -1,4 +1,4 @@
-.section .text.loader
+.section .stage1
 .code16
 loader_start:
 # set segment registers
@@ -37,7 +37,7 @@ _get_memory_size_use_ax:
 
 _get_memory_size_error:
     xchgw %bx, %bx
-    jmp loader_halt
+    jmp __stage1_halt
 
 _e820_mem_map_load:
     addl $4, %esp
@@ -96,49 +96,117 @@ _load_gdt:
 .code32
 
 start_32bit:
-    movw $16, %ax
+    movw $0x10, %ax
     movw %ax, %ds
     movw %ax, %es
     movw %ax, %fs
     movw %ax, %gs
     movw %ax, %ss
 
-# set up early stack at 0x001000000
-    movl $0x01000000, %ebp
-    movl $0x01000000, %esp
+    movl $0, %esp
+    movl $0, %ebp
 
 setup_early_kernel_page_table:
-# set up early kernel page table
-
-# the early kernel page directory is located at physical
-# address 0x00001000, size 4k, and the empty page is at
-# 0x0000-0x0fff, so we fill the first 6KiB
+# memory map:
+# 0x0000-0x1000: empty page
+# 0x1000-0x2000: early kernel pd
+# 0x2000-0x6000: 4 pts
+# 0x6000-0x8000: early kernel stack
+# so we fill the first 8KiB with zero
     movl $0x00000000, %eax
-    movl $0x6000, %ecx
-    call _fill_zero
+    movl $0x8000, %ecx
 
-# map the first 16MiB identically
-# 0x1000-0x1fff: early kernel pd
-# 0x2000-0x5fff: pde 0 - 4
-    movl $0x00001000, %eax
-    movl $0x00002003, %ebx
-_fill_pde_loop:
-    movl %ebx, (%eax)
+_fill_zero:
+    cmpl $0, %ecx
+    jz _fill_zero_end
+    subl $4, %ecx
+    movl $0, (%eax)
     addl $4, %eax
-    addl $0x1000, %ebx
-    cmpl $0x6003, %ebx
-    jne _fill_pde_loop
-
-# then, create page tables
-    movl $0x00000003, %eax
-    movl $0x00002000, %ecx
+    jmp _fill_zero
+_fill_zero_end:
 
-_create_page_table_loop1:
-    movl %eax, (%ecx)
-    addl $4, %ecx
-    addl $0x1000, %eax
-    cmpl $0x5ffc, %ecx
-    jle _create_page_table_loop1
+# pt#0: 0x00000000 to 0x00400000
+    movl $0x00001000, %eax
+    movl $0x00002003, (%eax)
+# pt#1: 0xc0000000 to 0xc0400000
+    movl $0x00001c00, %eax
+    movl $0x00003003, (%eax)
+# pt#2: 0xff000000 to 0xff400000
+    movl $0x00001ff0, %eax
+    movl $0x00004003, (%eax)
+# pt#3: 0xffc00000 to 0xffffffff
+    movl $0x00001ffc, %eax
+    movl $0x00005003, (%eax)
+
+# map early kernel page directory to 0xff000000
+    movl $0x00004000, %eax
+    movl $0x00001003, (%eax)
+
+# map kernel pt#2 to 0xff001000
+    movl $0x00004004, %eax
+    movl $0x00004003, (%eax)
+
+# map __stage1_start ---- __kinit_end identically
+    movl $__stage1_start, %ebx
+    movl $__kinit_end, %ecx
+    movl %ebx, %edx
+    shrl $12, %edx
+    andl $0x3ff, %edx
+
+
+__map_stage1_kinit:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00002000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_stage1_kinit
+
+# map __text_start ---- __data_end to 0xc0000000
+    movl %ecx, %ebx
+    movl $__text_start, %edx
+    shrl $12, %edx
+    andl $0x3ff, %edx
+
+    movl $__data_end, %ecx
+    subl $__text_start, %ecx
+    addl %ebx, %ecx
+
+__map_kernel_space:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00003000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_kernel_space
+
+# map __data_end ---- __bss_end from 0x100000
+    movl $0x100000, %ebx
+    movl $__bss_end, %ecx
+    subl $__data_end, %ecx
+    addl %ebx, %ecx
+
+__map_kernel_bss:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00003000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_kernel_bss
+
+# map kernel stack 0xffffe000-0xffffffff
+    movl $0x6000, %ebx
+    movl $0x8000, %ecx
+    movl $0x0ffffe, %edx
+    andl $0x3ff, %edx
+
+__map_kernel_stack:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00005000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_kernel_stack
 
 load_early_kernel_page_table:
     movl $0x00001000, %eax
@@ -149,60 +217,24 @@ load_early_kernel_page_table:
     orl $0x80010001, %eax
     movl %eax, %cr0
 
-    jmp start_move_kernel
-
-# quick call
-# %eax: address to fill
-# %ecx: byte count to fill
-_fill_zero:
-    movl %ecx, -4(%esp)
-    movl %eax, -8(%esp)
-
-_fill_zero_loop:
-    cmpl $0, %ecx
-    jz _fill_zero_end
-    subl $4, %ecx
-    movl $0, (%eax)
-    addl $4, %eax
-    jmp _fill_zero_loop
+# set stack pointer and clear stack bottom
+    movl $0xfffffff0, %esp
+    movl $0xfffffff0, %ebp
 
-_fill_zero_end:
-    movl -8(%esp), %eax
-    movl -4(%esp), %ecx
-    ret
-
-start_move_kernel:
-# move the kernel to 0x100000
-    movl $__loader_end, %eax
-    movl $__real_kernel_start, %ebx
-
-    movl $__p_kernel_text_and_data_size_addr, %ecx
-    movl (%ecx), %ecx
-    movl (%ecx), %ecx
-
-_move_kernel:
-    movl (%eax), %edx
-    movl %edx, (%ebx)
-    addl $4, %eax
-    addl $4, %ebx
-    subl $4, %ecx
-    cmpl $0, %ecx
-    jge _move_kernel
+    movl $0x00, (%esp)
+    movl $0x00, 4(%esp)
+    movl $0x00, 8(%esp)
+    movl $0x00, 12(%esp)
 
-    call kernel_main
+    call kernel_init
 
-loader_halt:
+__stage1_halt:
     hlt
-    jmp loader_halt
+    jmp __stage1_halt
 
 asm_gdt_descriptor:
     .word (5 * 8) - 1 # size
     .long asm_gdt_table  # address
-
-.globl asm_gdt_descriptor
-.type asm_gdt_descriptor @object
-.size asm_gdt_descriptor, (.-asm_gdt_descriptor)
-
 asm_gdt_table:
     .8byte 0         # null descriptor
 
@@ -238,26 +270,25 @@ asm_gdt_table:
     .byte 0b11001111 # flag and limit 16:20
     .byte 0x00       # base 24:31
 
-asm_mem_size_info:
-    .word 0x12
-    .word 0x34
-
 .globl asm_mem_size_info
 .type  asm_mem_size_info @object
 .size  asm_mem_size_info, (.-asm_mem_size_info)
+asm_mem_size_info:
+    .word 0x12
+    .word 0x34
 
-asm_e820_mem_map:
-    .space 1024
 .globl asm_e820_mem_map
 .type  asm_e820_mem_map @object
 .size  asm_e820_mem_map, (.-asm_e820_mem_map)
+asm_e820_mem_map:
+    .space 1024
 
-asm_e820_mem_map_count:
-    .long 0
 .globl asm_e820_mem_map_count
 .type  asm_e820_mem_map_count @object
-
-asm_e820_mem_map_entry_size:
+asm_e820_mem_map_count:
     .long 0
+
 .globl asm_e820_mem_map_entry_size
 .type  asm_e820_mem_map_entry_size @object
+asm_e820_mem_map_entry_size:
+    .long 0

+ 21 - 11
src/fs/fat.cpp

@@ -1,4 +1,5 @@
 #include <assert.h>
+#include <ctype.h>
 #include <fs/fat.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
@@ -9,6 +10,9 @@
 #include <types/hash_map.hpp>
 #include <types/status.h>
 
+#define VFAT_FILENAME_LOWERCASE (0x08)
+#define VFAT_EXTENSION_LOWERCASE (0x10)
+
 namespace fs::fat {
 // buf MUST be larger than 512 bytes
 inline void fat32::_raw_read_sector(void* buf, uint32_t sector_no)
@@ -40,7 +44,7 @@ char* fat32::read_cluster(cluster_t no)
         ++iter->value.ref;
         return iter->value.data;
     }
-    auto* data = (char*)k_malloc(sectors_per_cluster * SECTOR_SIZE);
+    auto* data = new char[sectors_per_cluster * SECTOR_SIZE];
     _raw_read_cluster(data, no);
     buf.emplace(no,
         buf_object {
@@ -73,8 +77,10 @@ int fat32::inode_readdir(fs::inode* dir, size_t offset, fs::vfs::filldir_func fi
         offset = 0;
         auto* end = d + (sectors_per_cluster * SECTOR_SIZE / sizeof(directory_entry));
         for (; d < end && d->filename[0]; ++d) {
-            if (d->attributes.volume_label)
+            if (d->attributes.volume_label) {
+                nread += sizeof(directory_entry);
                 continue;
+            }
 
             fs::ino_t ino = _rearrange(d);
             auto* ind = get_inode(ino);
@@ -92,16 +98,20 @@ int fat32::inode_readdir(fs::inode* dir, size_t offset, fs::vfs::filldir_func fi
             for (int i = 0; i < 8; ++i) {
                 if (d->filename[i] == ' ')
                     break;
-                fname += d->filename[i];
+                if (d->_reserved & VFAT_FILENAME_LOWERCASE)
+                    fname += tolower(d->filename[i]);
+                else
+                    fname += toupper(d->filename[i]);
             }
-            if (d->extension[0] != ' ') {
+            if (d->extension[0] != ' ')
                 fname += '.';
-                fname += d->extension[0];
-            }
             for (int i = 1; i < 3; ++i) {
                 if (d->extension[i] == ' ')
                     break;
-                fname += d->extension[i];
+                if (d->_reserved & VFAT_EXTENSION_LOWERCASE)
+                    fname += tolower(d->extension[i]);
+                else
+                    fname += toupper(d->extension[i]);
             }
             auto ret = filldir(fname.c_str(), 0, ind->ino,
                 (ind->flags.in.directory || ind->flags.in.mount_point) ? DT_DIR : DT_REG);
@@ -123,7 +133,7 @@ fat32::fat32(inode* _device)
     : device(_device)
     , label { 0 }
 {
-    char* buf = (char*)k_malloc(SECTOR_SIZE);
+    auto* buf = new char[SECTOR_SIZE];
     _raw_read_sector(buf, 0);
 
     auto* info = reinterpret_cast<ext_boot_sector*>(buf);
@@ -137,7 +147,7 @@ fat32::fat32(inode* _device)
     fat_copies = info->old.fat_copies;
 
     data_region_offset = reserved_sectors + fat_copies * sectors_per_fat;
-    fat = (cluster_t*)k_malloc(SECTOR_SIZE * sectors_per_fat);
+    fat = (cluster_t*)new char[SECTOR_SIZE * sectors_per_fat];
     // TODO: optimize
     for (uint32_t i = 0; i < 4; ++i)
         _raw_read_sector((char*)fat + i * SECTOR_SIZE, reserved_sectors + i);
@@ -157,7 +167,7 @@ fat32::fat32(inode* _device)
     free_clusters = fsinfo->free_clusters;
     next_free_cluster_hint = fsinfo->next_free_cluster;
 
-    k_free(buf);
+    delete[] buf;
 
     size_t _root_dir_clusters = 1;
     cluster_t next = root_dir;
@@ -173,7 +183,7 @@ fat32::fat32(inode* _device)
 
 fat32::~fat32()
 {
-    k_free(fat);
+    delete[]((char*)fat);
 }
 
 size_t fat32::inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n)

+ 77 - 26
src/kernel.ld

@@ -8,29 +8,28 @@ MEMORY
 
 SECTIONS
 {
-    .text.loader 0x7e00 : AT(0x00000000)
+    .stage1 0x8000 : AT(0x00000000)
     {
-        *(.text.loader)
-        __p_kernel_text_and_data_size_addr = .;
-        LONG(__loader_end + kernel_text_and_data_size - __real_kernel_start);
-        __loader_end = .;
+        __stage1_start = .;
+        *(.stage1)
+
+        . = ALIGN(0x1000);
+        __stage1_end = .;
     } > MEM
 
-    .text 0x100000 : AT(LOADADDR(.text.loader) + SIZEOF(.text.loader))
+    .kinit :
+        AT(LOADADDR(.stage1) + SIZEOF(.stage1))
     {
-        __real_kernel_start = .;
-        *(.text*)
-        *(.rodata*)
+        __kinit_start = .;
+        *(.text.kinit)
 
-        . = ALIGN(4);
-        kernel_text_and_data_size = .;
-        LONG(__kernel_text_and_data_end - ADDR(.text));
-        asm_kernel_size = .;
-        LONG(__real_kernel_end - ADDR(.text));
-        bss_section_start_addr = .;
-        LONG(ABSOLUTE(__bss_start));
-        bss_section_end_addr = .;
-        LONG(ABSOLUTE(__bss_end));
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        *(.rodata.kinit)
+
+        . = ALIGN(16);
 
         start_ctors = .;
         KEEP(*(.init_array));
@@ -39,25 +38,78 @@ SECTIONS
         KEEP(*(SORT_BY_INIT_PRIORITY(.ctors*)));
         end_ctors = .;
 
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        *(.data.kinit)
+
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        *(.bss.kinit)
+
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        . = ALIGN(0x1000);
+        __kinit_end = .;
+    } > MEM
+
+    .text 0xc0000000 :
+        AT(LOADADDR(.kinit) + SIZEOF(.kinit))
+    {
+        __text_start = .;
+        *(.text)
+        *(.text*)
+
+        . = ALIGN(0x1000);
+        __text_end = .;
+    } > MEM
+
+    .rodata :
+        AT(LOADADDR(.text) + SIZEOF(.text))
+    {
+        __rodata_start = .;
+        *(.rodata)
+        *(.rodata*)
+
+        . = ALIGN(16);
+
+        bss_addr = .;
+        LONG(ABSOLUTE(__bss_start));
+        bss_len = .;
+        LONG(__bss_end - __bss_start);
+        kernel_size = .;
+        LONG(__data_end - __kinit_start);
         __stack_chk_guard = .;
         LONG(0x19198101);
 
+        . = ALIGN(0x1000);
+        __rodata_end = .;
+    } > MEM
+
+    .data :
+        AT(LOADADDR(.rodata) + SIZEOF(.rodata))
+    {
+        __data_start = .;
         *(.data)
         *(.data*)
-        __kernel_text_and_data_end = .;
+
+        . = ALIGN(0x1000);
+        __data_end = .;
     } > MEM
 
-    .bss ALIGN(0x1000) :
+    .bss :
     {
         __bss_start = .;
         *(.bss)
         *(.bss*)
-        __bss_end = ALIGN(0x1000);
-    } > MEM
 
-    .kernel_end :
-    {
-        __real_kernel_end = .;
+        . = ALIGN(0x1000);
+        __bss_end = .;
     } > MEM
 
     /* Stabs debugging sections.  */
@@ -98,7 +150,6 @@ SECTIONS
     {
         *(.fini_array*)
         *(.eh_frame*)
-        *(.text.bootsect)
         *(.note*)
     }
 }

+ 29 - 38
src/kernel/event/event.cpp

@@ -17,7 +17,7 @@ namespace event {
 ::types::list<::input_event>& input_event_queue(void)
 {
     if (!_input_event_queue) {
-        _input_event_queue = types::pnew<types::kernel_allocator>(_input_event_queue);
+        _input_event_queue = new types::list<input_event>;
     }
     return *_input_event_queue;
 }
@@ -46,55 +46,46 @@ void dispatch_event(void)
     }
 }
 
-kernel::evtqueue::evtqueue(evtqueue&& q)
-    : m_evts { types::move(q.m_evts) }
-    , m_subscribers { types::move(q.m_subscribers) }
+bool kernel::cond_var::wait(types::mutex& lock)
 {
-}
+    thread* thd = current_thread;
 
-void kernel::evtqueue::push(kernel::evt&& event)
-{
-    types::lock_guard lck(m_mtx);
-    m_evts.push_back(types::move(event));
-    this->notify();
+    current_thread->attr.ready = 0;
+    current_thread->attr.wait = 1;
+    m_subscribers.push_back(thd);
+
+    lock.unlock();
+    bool ret = schedule();
+    lock.lock();
+
+    return ret;
 }
 
-kernel::evt kernel::evtqueue::front()
+void kernel::cond_var::notify(void)
 {
-    assert(!this->empty());
     types::lock_guard lck(m_mtx);
 
-    auto iter = m_evts.begin();
-    evt e = types::move(*iter);
-    m_evts.erase(iter);
-    return e;
-}
+    auto iter = m_subscribers.begin();
+    if (iter == m_subscribers.end())
+        return;
 
-const kernel::evt* kernel::evtqueue::peek(void) const
-{
-    return &m_evts.begin();
-}
+    auto* thd = *iter;
+    thd->attr.ready = 1;
+    thd->attr.wait = 0;
+    readythds->push(thd);
 
-bool kernel::evtqueue::empty(void) const
-{
-    return m_evts.empty();
+    m_subscribers.erase(iter);
 }
 
-void kernel::evtqueue::notify(void)
+void kernel::cond_var::notify_all(void)
 {
-    for (auto* sub : m_subscribers) {
-        sub->attr.ready = 1;
-        sub->attr.wait = 0;
-        readythds->push(sub);
-    }
-}
+    types::lock_guard lck(m_mtx);
 
-void kernel::evtqueue::subscribe(thread* thd)
-{
-    m_subscribers.push_back(thd);
-}
+    for (auto& thd : m_subscribers) {
+        thd->attr.ready = 1;
+        thd->attr.wait = 0;
+        readythds->push(thd);
+    }
 
-void kernel::evtqueue::unsubscribe(thread* thd)
-{
-    m_subscribers.erase(m_subscribers.find(thd));
+    m_subscribers.clear();
 }

+ 6 - 4
src/kernel/hw/ata.cpp

@@ -182,6 +182,7 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
     struct mbr hda_mbr {
     };
     auto* dev = fs::vfs_open("/dev");
+    assert(dev);
 
     fs::vfs_read(drive, (char*)&hda_mbr, 512, 0, 512);
 
@@ -201,13 +202,13 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
 // data: void (*func_to_call_next)(void)
 void hw::init_ata(void)
 {
-    ata_pri = types::pnew<types::kernel_allocator>(ata_pri, ATA_PRIMARY_BUS_BASE);
+    ata_pri = new hw::ata(ATA_PRIMARY_BUS_BASE);
     if (ata_pri->identify())
         ata_pri->select(true);
 
-    ata_sec = types::pnew<types::kernel_allocator>(ata_pri, ATA_SECONDARY_BUS_BASE);
-    if (ata_pri->identify())
-        ata_pri->select(true);
+    ata_sec = new hw::ata(ATA_SECONDARY_BUS_BASE);
+    if (ata_sec->identify())
+        ata_sec->select(true);
 
     // data1: offset sectors
     // data2: limit sectors
@@ -228,5 +229,6 @@ void hw::init_ata(void)
         0xffffffff);
 
     auto* hda = fs::vfs_open("/dev/hda");
+    assert(hda);
     mbr_part_probe(hda->ind, 2, 1);
 }

+ 1 - 0
src/kernel/hw/serial.cpp

@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <types/status.h>
 
+SECTION(".text.kinit")
 int32_t init_serial_port(port_id_t port)
 {
     // taken from osdev.org

+ 1 - 0
src/kernel/hw/timer.c

@@ -3,6 +3,7 @@
 
 static time_t _current_ticks = 0;
 
+SECTION(".text.kinit")
 void init_pit(void)
 {
     // set interval

+ 65 - 35
src/kernel/interrupt.cpp

@@ -10,10 +10,8 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/syscall.hpp>
 #include <kernel/vfs.hpp>
 #include <kernel/vga.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <types/size.h>
@@ -37,6 +35,7 @@ static inline void NORETURN die(regs_32& regs, ptr_t eip)
     freeze();
 }
 
+SECTION(".text.kinit")
 void init_idt()
 {
     asm_cli();
@@ -53,7 +52,6 @@ void init_idt()
     SET_IDT_ENTRY_FN(14, int14, 0x08, KERNEL_INTERRUPT_GATE_TYPE);
     // system call
     SET_IDT_ENTRY_FN(0x80, syscall_stub, 0x08, USER_INTERRUPT_GATE_TYPE);
-    init_syscall();
 
     uint16_t idt_descriptor[3];
     idt_descriptor[0] = sizeof(struct IDT_entry) * 256;
@@ -62,6 +60,7 @@ void init_idt()
     asm_load_idt(idt_descriptor, 0);
 }
 
+SECTION(".text.kinit")
 void init_pic(void)
 {
     asm_cli();
@@ -183,30 +182,34 @@ extern "C" void int14_handler(int14_data* d)
     if (unlikely(d->error_code.user && mm_area->attr.in.system))
         _int14_kill_user();
 
-    pte_t* pte = to_pte(mms->m_pd, d->l_addr);
-    page* page = lto_page(&mm_area, d->l_addr);
+    page* page = &mm_area->pgs->at(vptrdiff(d->l_addr, mm_area->start) / PAGE_SIZE);
+    kernel::paccess pa(page->pg_pteidx >> 12);
+    auto pt = (pt_t)pa.ptr();
+    assert(pt);
+    pte_t* pte = *pt + (page->pg_pteidx & 0xfff);
 
     if (unlikely(d->error_code.present == 0 && !mm_area->mapped_file))
         _int14_panic(d->v_eip, d->l_addr, d->error_code);
 
-    // copy on write
-    if (page->attr.in.cow == 1) {
+    if (page->attr & PAGE_COW) {
         // if it is a dying page
         if (*page->ref_count == 1) {
-            page->attr.in.cow = 0;
+            page->attr &= ~PAGE_COW;
+            pte->in.p = 1;
             pte->in.a = 0;
             pte->in.rw = mm_area->attr.in.write;
             return;
         }
         // duplicate the page
-        page_t new_page = alloc_raw_page();
-
-        // memory mapped
-        if (d->error_code.present == 0)
-            pte->in.p = 1;
-
-        char* new_page_data = (char*)to_vp(new_page);
-        memcpy(new_page_data, to_vp(page->phys_page_id), PAGE_SIZE);
+        page_t new_page = __alloc_raw_page();
+
+        {
+            kernel::paccess pdst(new_page), psrc(page->phys_page_id);
+            auto* new_page_data = (char*)pdst.ptr();
+            auto* src = psrc.ptr();
+            assert(new_page_data && src);
+            memcpy(new_page_data, src, PAGE_SIZE);
+        }
 
         pte->in.page = new_page;
         pte->in.rw = mm_area->attr.in.write;
@@ -214,105 +217,132 @@ extern "C" void int14_handler(int14_data* d)
 
         --*page->ref_count;
 
-        page->ref_count = (size_t*)ki_malloc(sizeof(size_t));
-        *page->ref_count = 1;
-        page->attr.in.cow = 0;
+        page->ref_count = types::pnew<types::kernel_ident_allocator>(page->ref_count, 1);
+        page->attr &= ~PAGE_COW;
         page->phys_page_id = new_page;
+    }
 
-        // memory mapped
-        if (d->error_code.present == 0) {
-            size_t offset = align_down<12>((uint32_t)d->l_addr);
-            offset -= (uint32_t)mm_area->start;
-
-            int n = vfs_read(
-                mm_area->mapped_file,
-                new_page_data,
-                PAGE_SIZE,
-                mm_area->file_offset + offset,
-                PAGE_SIZE);
-
-            // TODO: send SIGBUS if offset is greater than real size
-            if (n != PAGE_SIZE)
-                memset(new_page_data + n, 0x00, PAGE_SIZE - n);
-        }
+    if (page->attr & PAGE_MMAP) {
+        pte->in.p = 1;
+
+        size_t offset = align_down<12>((uint32_t)d->l_addr);
+        offset -= (uint32_t)mm_area->start;
+
+        kernel::paccess pa(page->phys_page_id);
+        auto* data = (char*)pa.ptr();
+        assert(data);
+
+        int n = vfs_read(
+            mm_area->mapped_file,
+            data,
+            PAGE_SIZE,
+            mm_area->file_offset + offset,
+            PAGE_SIZE);
+
+        // TODO: send SIGBUS if offset is greater than real size
+        if (n != PAGE_SIZE)
+            memset(data + n, 0x00, PAGE_SIZE - n);
+
+        page->attr &= ~PAGE_MMAP;
     }
 }
 
+void after_irq(void)
+{
+    check_signal();
+}
+
 extern "C" void irq0_handler(interrupt_stack*)
 {
     inc_tick();
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
     schedule();
+    after_irq();
 }
 // keyboard interrupt
 extern "C" void irq1_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
     handle_keyboard_interrupt();
+    after_irq();
 }
 extern "C" void irq2_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq3_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq4_handler(void)
 {
     // TODO: register interrupt handler in serial port driver
     serial_receive_data_interrupt();
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq5_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq6_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq7_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq8_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq9_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq10_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq11_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq12_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq13_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq14_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }
 extern "C" void irq15_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+    after_irq();
 }

+ 216 - 350
src/kernel/mem.cpp

@@ -1,4 +1,3 @@
-#include <asm/boot.h>
 #include <asm/port_io.h>
 #include <asm/sys.h>
 #include <assert.h>
@@ -8,7 +7,6 @@
 #include <kernel/process.hpp>
 #include <kernel/task.h>
 #include <kernel/vga.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <types/allocator.hpp>
@@ -18,221 +16,59 @@
 
 // constant values
 
-#define EMPTY_PAGE_ADDR ((pptr_t)0x0000)
-#define EMPTY_PAGE_END ((pptr_t)0x1000)
-
-#define IDENTICALLY_MAPPED_HEAP_SIZE ((size_t)0x400000)
+#define EMPTY_PAGE ((page_t)0)
 
 // ---------------------
 
 static size_t mem_size;
-static char mem_bitmap[1024 * 1024 / 8];
-
-class brk_memory_allocator {
-public:
-    using byte = uint8_t;
-    using size_type = size_t;
-
-    struct mem_blk_flags {
-        uint8_t is_free;
-        uint8_t has_next;
-        uint8_t _unused2;
-        uint8_t _unused3;
-    };
-
-    struct mem_blk {
-        size_t size;
-        struct mem_blk_flags flags;
-        // the first byte of the memory space
-        // the minimal allocated space is 4 bytes
-        uint8_t data[4];
-    };
-
-private:
-    byte* p_start;
-    byte* p_break;
-    byte* p_limit;
-
-    brk_memory_allocator(void) = delete;
-    brk_memory_allocator(const brk_memory_allocator&) = delete;
-    brk_memory_allocator(brk_memory_allocator&&) = delete;
-
-    inline constexpr int brk(byte* addr)
-    {
-        if (unlikely(addr >= p_limit))
-            return GB_FAILED;
-        p_break = addr;
-        return GB_OK;
-    }
-
-    // sets errno
-    inline byte* sbrk(size_type increment)
-    {
-        if (unlikely(brk(p_break + increment) != GB_OK)) {
-            errno = ENOMEM;
-            return nullptr;
-        } else {
-            errno = 0;
-            return p_break;
-        }
-    }
-
-    inline mem_blk* _find_next_mem_blk(mem_blk* blk, size_type blk_size)
-    {
-        byte* p = (byte*)blk;
-        p += sizeof(mem_blk);
-        p += blk_size;
-        p -= (4 * sizeof(byte));
-        return (mem_blk*)p;
-    }
-
-    // sets errno
-    // @param start_pos position where to start finding
-    // @param size the size of the block we're looking for
-    // @return found block if suitable block exists, if not, the last block
-    mem_blk* find_blk(mem_blk* start_pos, size_type size)
-    {
-        while (1) {
-            if (start_pos->flags.is_free && start_pos->size >= size) {
-                errno = 0;
-                return start_pos;
-            } else {
-                if (unlikely(!start_pos->flags.has_next)) {
-                    errno = ENOTFOUND;
-                    return start_pos;
-                }
-                start_pos = _find_next_mem_blk(start_pos, start_pos->size);
-            }
-        }
-    }
-
-    // sets errno
-    mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
-    {
-        sbrk(sizeof(mem_blk) + size - 4 * sizeof(byte));
-        // preserves errno
-        if (unlikely(errno)) {
-            return nullptr;
-        }
-
-        mem_blk* blk = _find_next_mem_blk(blk_before, blk_before->size);
-
-        blk_before->flags.has_next = 1;
-
-        blk->flags.has_next = 0;
-        blk->flags.is_free = 1;
-        blk->size = size;
-
-        errno = 0;
-        return blk;
-    }
-
-    void split_block(mem_blk* blk, size_type this_size)
-    {
-        // block is too small to get split
-        if (blk->size < sizeof(mem_blk) + this_size) {
-            return;
-        }
+static uint8_t mem_bitmap[1024 * 1024 / 8];
 
-        mem_blk* blk_next = _find_next_mem_blk(blk, this_size);
+// global
+segment_descriptor gdt[6];
 
-        blk_next->size = blk->size
-            - this_size
-            - sizeof(mem_blk)
-            + 4 * sizeof(byte);
+uint8_t e820_mem_map[1024];
+uint32_t e820_mem_map_count;
+uint32_t e820_mem_map_entry_size;
+struct mem_size_info mem_size_info;
 
-        blk_next->flags.has_next = blk->flags.has_next;
-        blk_next->flags.is_free = 1;
-
-        blk->flags.has_next = 1;
-        blk->size = this_size;
-    }
-
-public:
-    brk_memory_allocator(void* start, size_type limit)
-        : p_start((byte*)start)
-        , p_limit(p_start + limit)
-    {
-        brk(p_start);
-        mem_blk* p_blk = (mem_blk*)sbrk(0);
-        p_blk->size = 4;
-        p_blk->flags.has_next = 0;
-        p_blk->flags.is_free = 1;
-    }
-
-    // sets errno
-    void* alloc(size_type size)
-    {
-        struct mem_blk* block_allocated;
-
-        block_allocated = find_blk((mem_blk*)p_start, size);
-        if (errno == ENOTFOUND) {
-            // 'block_allocated' in the argument list is the pointer
-            // pointing to the last block
-            block_allocated = allocate_new_block(block_allocated, size);
-            if (errno) {
-                // preserves errno
-                return nullptr;
-            }
-        } else {
-            split_block(block_allocated, size);
-        }
-
-        errno = 0;
-        block_allocated->flags.is_free = 0;
-        return block_allocated->data;
-    }
-
-    void free(void* ptr)
-    {
-        mem_blk* blk = (mem_blk*)((byte*)ptr - (sizeof(mem_blk_flags) + sizeof(size_t)));
-        blk->flags.is_free = 1;
-        // TODO: fusion free blocks nearby
-    }
-};
-
-static brk_memory_allocator* kernel_heap_allocator;
-static brk_memory_allocator
-    kernel_ident_mapped_allocator((void*)bss_section_end_addr,
-        IDENTICALLY_MAPPED_HEAP_SIZE);
+void* operator new(size_t sz)
+{
+    void* ptr = types::__allocator::m_palloc->alloc(sz);
+    assert(ptr);
+    return ptr;
+}
 
-void* k_malloc(size_t size)
+void* operator new[](size_t sz)
 {
-    void* ptr = kernel_heap_allocator->alloc(size);
-    assert(likely(ptr));
+    void* ptr = types::__allocator::m_palloc->alloc(sz);
+    assert(ptr);
     return ptr;
 }
 
-void k_free(void* ptr)
+void operator delete(void* ptr)
 {
-    kernel_heap_allocator->free(ptr);
+    types::__allocator::m_palloc->free(ptr);
 }
 
-void* ki_malloc(size_t size)
+void operator delete(void* ptr, size_t)
 {
-    void* ptr = kernel_ident_mapped_allocator.alloc(size);
-    assert(likely(ptr));
-    return ptr;
+    types::__allocator::m_palloc->free(ptr);
 }
 
-void ki_free(void* ptr)
+void operator delete[](void* ptr)
 {
-    kernel_ident_mapped_allocator.free(ptr);
+    types::__allocator::m_palloc->free(ptr);
 }
 
-void* ptovp(pptr_t p_ptr)
+void operator delete[](void* ptr, size_t)
 {
-    // memory below 768MiB is identically mapped
-    // TODO: address translation for high mem
-    assert(p_ptr <= 0x30000000);
-    return (void*)p_ptr;
+    types::__allocator::m_palloc->free(ptr);
 }
 
 inline void mark_page(page_t n)
 {
     bm_set(mem_bitmap, n);
 }
-
 inline void free_page(page_t n)
 {
     bm_clear(mem_bitmap, n);
@@ -240,130 +76,113 @@ inline void free_page(page_t n)
 
 constexpr void mark_addr_len(pptr_t start, size_t n)
 {
-    if (unlikely(n == 0))
+    if (n == 0)
         return;
-    page_t start_page = to_page(start);
-    page_t end_page = to_page(start + n + 4095);
+    page_t start_page = align_down<12>(start) >> 12;
+    page_t end_page = align_up<12>(start + n) >> 12;
     for (page_t i = start_page; i < end_page; ++i)
         mark_page(i);
 }
 
 constexpr void free_addr_len(pptr_t start, size_t n)
 {
-    if (unlikely(n == 0))
+    if (n == 0)
         return;
-    page_t start_page = to_page(start);
-    page_t end_page = to_page(start + n + 4095);
+    page_t start_page = align_down<12>(start) >> 12;
+    page_t end_page = align_up<12>(start + n) >> 12;
     for (page_t i = start_page; i < end_page; ++i)
         free_page(i);
 }
 
-inline constexpr void mark_addr_range(pptr_t start, pptr_t end)
+constexpr void mark_addr_range(pptr_t start, pptr_t end)
 {
     mark_addr_len(start, end - start);
 }
 
-inline constexpr void free_addr_range(pptr_t start, pptr_t end)
+constexpr void free_addr_range(pptr_t start, pptr_t end)
 {
     free_addr_len(start, end - start);
 }
 
-// @return the max count (but less than n) of the pages continuously available
-static inline size_t _test_n_raw_pages(page_t start, size_t n)
-{
-    // *start is already allocated
-    if (bm_test(mem_bitmap, start))
-        return 0;
-
-    return 1 + ((n > 1) ? _test_n_raw_pages(start + 1, n - 1) : 0);
-}
-
-page_t alloc_n_raw_pages(size_t n)
+page_t __alloc_raw_page(void)
 {
-    page_t first = 0;
-    while (first <= 1024 * 1024 - n) {
-        size_t max = _test_n_raw_pages(first, n);
-        if (max != n) {
-            first += (max + 1);
-        } else {
-            for (page_t i = first; i < first + n; ++i)
-                mark_page(i);
-            return first;
+    for (size_t i = 0; i < sizeof(mem_bitmap); ++i) {
+        if (bm_test(mem_bitmap, i) == 0) {
+            bm_set(mem_bitmap, i);
+            return i;
         }
     }
-    assert(false);
-    return 0xffffffff;
+    return -1;
 }
 
-void free_n_raw_pages(page_t start_pg, size_t n)
+void __free_raw_page(page_t pg)
 {
-    while (n--)
-        free_page(start_pg++);
+    bm_clear(mem_bitmap, pg);
 }
 
-struct page allocate_page(void)
+page allocate_page(void)
 {
     return page {
-        .phys_page_id = alloc_raw_page(),
-        .pte = nullptr,
+        .phys_page_id = __alloc_raw_page(),
         .ref_count = types::_new<types::kernel_ident_allocator, size_t>(0),
-        .attr { 0 },
+        .pg_pteidx = 0,
+        .attr = 0,
     };
 }
 
-pd_t alloc_pd(void)
-{
-    // TODO: alloc page in low mem and gen struct page for it
-    page_t pd_page = alloc_raw_page();
-    pd_t pd = to_pd(pd_page);
-    memset(pd, 0x00, PAGE_SIZE);
-    return pd;
-}
-
-pt_t alloc_pt(void)
+void free_page(page* pg)
 {
-    // TODO: alloc page in low mem and gen struct page for it
-    page_t pt_page = alloc_raw_page();
-    pt_t pt = to_pt(pt_page);
-    memset(pt, 0x00, PAGE_SIZE);
-    return pt;
+    if (*pg->ref_count == 1) {
+        types::pdelete<types::kernel_ident_allocator>(pg->ref_count);
+        __free_raw_page(pg->phys_page_id);
+    } else {
+        --*pg->ref_count;
+    }
 }
 
-void dealloc_pd(pd_t pd)
+void dealloc_pd(page_t pd)
 {
-    for (pde_t* ent = (*pd) + 256; ent < (*pd) + 1024; ++ent) {
-        if (!ent->in.p)
-            continue;
-        dealloc_pt(to_pt(ent));
+    {
+        kernel::paccess pa(pd);
+        auto p_pd = (pd_t)pa.ptr();
+        assert(p_pd);
+        for (pde_t* ent = (*p_pd); ent < (*p_pd) + 768; ++ent) {
+            if (!ent->in.p)
+                continue;
+            __free_raw_page(ent->in.pt_page);
+        }
     }
-    memset(pd, 0x00, sizeof(*pd));
-
-    page_t pg = to_page((pptr_t)pd);
-    free_page(pg);
-}
-void dealloc_pt(pt_t pt)
-{
-    memset(pt, 0x00, sizeof(*pt));
-
-    page_t pg = to_page((pptr_t)pt);
-    free_page(pg);
+    __free_raw_page(pd);
 }
 
+SECTION(".text.kinit")
 static inline void init_mem_layout(void)
 {
     mem_size = 1024 * mem_size_info.n_1k_blks;
     mem_size += 64 * 1024 * mem_size_info.n_64k_blks;
 
-    // mark kernel page directory
-    mark_addr_range(0x00001000, 0x00006000);
     // mark empty page
-    mark_addr_range(EMPTY_PAGE_ADDR, EMPTY_PAGE_END);
+    mark_addr_range(0x00000000, 0x00001000);
+    // mark kernel page directory
+    mark_addr_range(0x00001000, 0x00002000);
+    // mark kernel page table
+    mark_addr_range(0x00002000, 0x00006000);
+    // mark kernel early stack
+    mark_addr_range(0x00006000, 0x00008000);
     // mark EBDA and upper memory as allocated
-    mark_addr_range(0x80000, 0xfffff);
-    // mark kernel
-    mark_addr_len(0x00100000, kernel_size);
-    // mark identically mapped heap
-    mark_addr_len(bss_section_end_addr, IDENTICALLY_MAPPED_HEAP_SIZE);
+    mark_addr_range(0x80000, 0x100000);
+    extern char __stage1_start[];
+    extern char __kinit_end[];
+    extern char __text_start[];
+    extern char __data_end[];
+
+    constexpr pptr_t PHYS_BSS_START = 0x100000;
+    // mark .stage1 and .kinit
+    mark_addr_range((pptr_t)__stage1_start, (pptr_t)__kinit_end);
+    // mark kernel .text to .data
+    mark_addr_len((pptr_t)__kinit_end, __data_end - __text_start);
+    // mark kernel .bss
+    mark_addr_len(PHYS_BSS_START, bss_len);
 
     if (e820_mem_map_entry_size == 20) {
         struct e820_mem_map_entry_20* entry = (struct e820_mem_map_entry_20*)e820_mem_map;
@@ -386,9 +205,12 @@ using kernel::mm_list;
 mm_list::mm_list(const mm_list& v)
     : m_areas(v.m_areas)
 {
-    pd_t pd = alloc_pd();
-    memcpy(pd, v.m_pd, PAGE_SIZE);
-    m_pd = pd;
+    m_pd = __alloc_raw_page();
+    kernel::paccess pdst(m_pd), psrc(v.m_pd);
+    auto* dst = pdst.ptr();
+    auto* src = psrc.ptr();
+    assert(dst && src);
+    memcpy(dst, src, PAGE_SIZE);
 }
 
 inline void map_raw_page_to_pte(
@@ -406,40 +228,70 @@ inline void map_raw_page_to_pte(
     pte->in.page = page;
 }
 
-int mm::append_page(page* pg, bool present, bool write, bool priv, bool cow)
+int mm::append_page(page& pg, uint32_t attr, bool priv)
 {
     void* addr = this->end();
-    pde_t* pde = to_pde(this->owner->m_pd, addr);
+    kernel::paccess pa(this->owner->m_pd);
+    auto pd = (pd_t)pa.ptr();
+    assert(pd);
+    pde_t* pde = *pd + v_to_pdi(addr);
+
+    page_t pt_pg = 0;
+    pte_t* pte = nullptr;
     // page table not exist
     if (unlikely(!pde->in.p)) {
         // allocate a page for the page table
+        pt_pg = __alloc_raw_page();
         pde->in.p = 1;
         pde->in.rw = 1;
         pde->in.us = 1;
-        pde->in.pt_page = alloc_raw_page();
+        pde->in.pt_page = pt_pg;
+
+        auto pt = (pt_t)kernel::pmap(pt_pg);
+        assert(pt);
+        pte = *pt;
 
-        memset(to_pt(pde), 0x00, PAGE_SIZE);
+        memset(pt, 0x00, PAGE_SIZE);
+    } else {
+        pt_pg = pde->in.pt_page;
+        auto pt = (pt_t)kernel::pmap(pt_pg);
+        assert(pt);
+        pte = *pt;
     }
 
     // map the page in the page table
-    pte_t* pte = to_pte(pde, addr);
-    map_raw_page_to_pte(pte, pg->phys_page_id, present, (write && !cow), priv);
-
-    if (unlikely(cow && !pg->attr.in.cow)) {
-        pg->attr.in.cow = 1;
-        pg->pte->in.rw = 0;
-        pg->pte->in.a = 0;
+    int pti = v_to_pti(addr);
+    pte += pti;
+
+    map_raw_page_to_pte(
+        pte,
+        pg.phys_page_id,
+        !(attr & PAGE_MMAP),
+        false,
+        priv);
+
+    kernel::pfree(pt_pg);
+
+    if (unlikely((attr & PAGE_COW) && !(pg.attr & PAGE_COW))) {
+        kernel::paccess pa(pg.pg_pteidx >> 12);
+        auto* pg_pte = (pte_t*)pa.ptr();
+        assert(pg_pte);
+        pg_pte += (pg.pg_pteidx & 0xfff);
+        pg.attr |= PAGE_COW;
+        pg_pte->in.rw = 0;
+        pg_pte->in.a = 0;
         invalidate_tlb(addr);
     }
-    ++*pg->ref_count;
+    ++*pg.ref_count;
+
+    auto iter = this->pgs->emplace_back(pg);
+    iter->pg_pteidx = (pt_pg << 12) + pti;
+    iter->attr = attr;
 
-    auto iter = this->pgs->emplace_back(*pg);
-    iter->pte = pte;
     return GB_OK;
 }
 
-static inline int _mmap(
-    mm_list* mms,
+int mmap(
     void* hint,
     size_t len,
     fs::inode* file,
@@ -447,6 +299,8 @@ static inline int _mmap(
     int write,
     int priv)
 {
+    auto& mms = current_process->mms;
+
     if (unlikely(!file->flags.in.file && !file->flags.in.special_node)) {
         errno = EINVAL;
         return GB_FAILED;
@@ -459,93 +313,45 @@ static inline int _mmap(
 
     size_t n_pgs = align_up<12>(len) >> 12;
 
-    if (!mms->is_avail(hint, len)) {
+    if (!mms.is_avail(hint, len)) {
         errno = EEXIST;
         return GB_FAILED;
     }
 
-    auto mm = mms->addarea(hint, write, priv);
+    auto mm = mms.addarea(hint, write, priv);
     mm->mapped_file = file;
     mm->file_offset = offset;
 
     for (size_t i = 0; i < n_pgs; ++i)
-        mm->append_page(&empty_page, false, write, priv, true);
+        mm->append_page(empty_page, PAGE_MMAP | PAGE_COW, priv);
 
     return GB_OK;
 }
 
-int mmap(
-    void* hint,
-    size_t len,
-    fs::inode* file,
-    size_t offset,
-    int write,
-    int priv)
-{
-    return _mmap(&current_process->mms, hint, len, file, offset, write, priv);
-}
-
-// map a page identically
-// this function is only meant to be used in the initialization process
-// it checks the pde's P bit so you need to make sure it's already set
-// to avoid dead loops
-static inline void _init_map_page_identically(page_t page)
-{
-    pde_t* pde = *KERNEL_PAGE_DIRECTORY_ADDR + to_pdi(page);
-    // page table not exist
-    if (unlikely(!pde->in.p)) {
-        // allocate a page for the page table
-        // set the P bit of the pde in advance
-        pde->in.p = 1;
-        pde->in.rw = 1;
-        pde->in.us = 0;
-        pde->in.pt_page = alloc_raw_page();
-        _init_map_page_identically(pde->in.pt_page);
-        memset(to_pt(pde), 0x00, PAGE_SIZE);
-    }
-
-    // map the page in the page table
-    pte_t* pt = to_pte(pde, page);
-    pt->v = 0x00000003;
-    pt->in.page = page;
-}
-
-static inline void init_paging_map_low_mem_identically(void)
-{
-    for (pptr_t addr = 0x01000000; addr < 0x30000000; addr += 0x1000) {
-        // check if the address is valid and not mapped
-        if (bm_test(mem_bitmap, to_page(addr)))
-            continue;
-        _init_map_page_identically(to_page(addr));
-    }
-}
-
+SECTION(".text.kinit")
 void init_mem(void)
 {
     init_mem_layout();
 
-    // map the 16MiB-768MiB identically
-    init_paging_map_low_mem_identically();
-
-    kernel_mms = types::pnew<types::kernel_ident_allocator>(kernel_mms, KERNEL_PAGE_DIRECTORY_ADDR);
+    // TODO: replace early kernel pd
+    kernel_mms = types::pnew<types::kernel_ident_allocator>(kernel_mms, EARLY_KERNEL_PD_PAGE);
     auto heap_mm = kernel_mms->addarea(KERNEL_HEAP_START, true, true);
 
     // create empty_page struct
-    empty_page.attr.in.cow = 0;
-    empty_page.phys_page_id = to_page(EMPTY_PAGE_ADDR);
-    empty_page.ref_count = types::_new<types::kernel_ident_allocator, size_t>(1);
-    empty_page.pte = to_pte(*KERNEL_PAGE_DIRECTORY_ADDR, empty_page.phys_page_id);
-    empty_page.pte->in.rw = 0;
-    invalidate_tlb(0x00000000);
-
-    // 0x30000000 to 0x40000000 or 768MiB to 1GiB
-    while (heap_mm->pgs->size() < 256 * 1024 * 1024 / PAGE_SIZE)
-        heap_mm->append_page(&empty_page, true, true, true, true);
-
-    kernel_heap_allocator = types::pnew<types::kernel_ident_allocator>(kernel_heap_allocator,
-        KERNEL_HEAP_START, vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
+    empty_page.attr = 0;
+    empty_page.phys_page_id = EMPTY_PAGE;
+    empty_page.ref_count = types::_new<types::kernel_ident_allocator, size_t>(2);
+    empty_page.pg_pteidx = 0x00002000;
+
+    // 0xd0000000 to 0xd4000000 or 3.5GiB, size 64MiB
+    while (heap_mm->pgs->size() < 64 * 1024 * 1024 / PAGE_SIZE)
+        heap_mm->append_page(empty_page, PAGE_COW, true);
+
+    types::__allocator::init_kernel_heap(KERNEL_HEAP_START,
+        vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
 }
 
+SECTION(".text.kinit")
 void create_segment_descriptor(
     segment_descriptor* sd,
     uint32_t base,
@@ -561,3 +367,63 @@ void create_segment_descriptor(
     sd->access = access;
     sd->flags = flags;
 }
+
+namespace __physmapper {
+struct mapped_area {
+    size_t ref;
+    uint8_t* ptr;
+};
+
+static types::hash_map<page_t, mapped_area,
+    types::linux_hasher<page_t>, types::kernel_ident_allocator>
+    mapped;
+static uint8_t freebm[0x400 / 8];
+} // namespace __physmapper
+
+uint8_t* kernel::pmap(page_t pg)
+{
+    auto iter = __physmapper::mapped.find(pg);
+    if (iter) {
+        ++iter->value.ref;
+        return iter->value.ptr;
+    }
+
+    for (int i = 2; i < 0x400; ++i) {
+        if (bm_test(__physmapper::freebm, i) == 0) {
+            auto* pte = (pte_t*)(0xff001000) + i;
+            pte->v = 0x3;
+            pte->in.page = pg;
+
+            uint8_t* ptr = (uint8_t*)0xff000000 + 0x1000 * i;
+            invalidate_tlb(ptr);
+
+            bm_set(__physmapper::freebm, i);
+            __physmapper::mapped.emplace(pg,
+                __physmapper::mapped_area { 1, ptr });
+            return ptr;
+        }
+    }
+
+    return nullptr;
+}
+void kernel::pfree(page_t pg)
+{
+    auto iter = __physmapper::mapped.find(pg);
+    if (!iter)
+        return;
+
+    if (iter->value.ref > 1) {
+        --iter->value.ref;
+        return;
+    }
+
+    int i = (uint32_t)iter->value.ptr - 0xff000000;
+    i /= 0x1000;
+
+    auto* pte = (pte_t*)(0xff001000) + i;
+    pte->v = 0;
+    invalidate_tlb(iter->value.ptr);
+
+    bm_clear(__physmapper::freebm, i);
+    __physmapper::mapped.remove(iter);
+}

+ 149 - 28
src/kernel/process.cpp

@@ -8,11 +8,12 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
+#include <kernel/signal.hpp>
 #include <kernel/vfs.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <types/allocator.hpp>
+#include <types/bitmap.h>
 #include <types/cplusplus.hpp>
 #include <types/elf.hpp>
 #include <types/hash_map.hpp>
@@ -45,42 +46,95 @@ struct no_irq_guard {
 
 } // namespace kernel
 
+namespace __thd {
+inline uint8_t __kstack_bmp[(0x1000000 - 0xc00000) / 0x2000 / 8];
+inline int __allocated;
+} // namespace __thd
+
+void thread::alloc_kstack(void)
+{
+    for (int i = 0; i < __thd::__allocated; ++i) {
+        if (bm_test(__thd::__kstack_bmp, i) == 0) {
+            pkstack = 0xffc00000 + THREAD_KERNEL_STACK_SIZE * (i + 1);
+            esp = reinterpret_cast<uint32_t*>(pkstack);
+
+            bm_set(__thd::__kstack_bmp, i);
+            return;
+        }
+    }
+
+    // kernel stack pt is at page#0x00005
+    kernel::paccess pa(0x00005);
+    auto pt = (pt_t)pa.ptr();
+    assert(pt);
+    pte_t* pte = *pt + __thd::__allocated * 2;
+
+    pte[0].v = 0x3;
+    pte[0].in.page = __alloc_raw_page();
+    pte[1].v = 0x3;
+    pte[1].in.page = __alloc_raw_page();
+
+    pkstack = 0xffc00000 + THREAD_KERNEL_STACK_SIZE * (__thd::__allocated + 1);
+    esp = reinterpret_cast<uint32_t*>(pkstack);
+
+    bm_set(__thd::__kstack_bmp, __thd::__allocated);
+    ++__thd::__allocated;
+}
+
+void thread::free_kstack(uint32_t p)
+{
+    p -= 0xffc00000;
+    p /= THREAD_KERNEL_STACK_SIZE;
+    p -= 1;
+    bm_clear(__thd::__kstack_bmp, p);
+}
+
 process::process(process&& val)
     : mms(types::move(val.mms))
     , thds { types::move(val.thds), this }
-    , wait_lst(types::move(val.wait_lst))
     , attr { val.attr }
+    , files(types::move(val.files))
+    , pwd(types::move(val.pwd))
     , pid(val.pid)
     , ppid(val.ppid)
-    , files(types::move(val.files))
+    , pgid(val.pgid)
+    , sid(val.sid)
 {
     if (current_process == &val)
         current_process = this;
-
-    val.pid = 0;
-    val.ppid = 0;
-    val.attr.system = 0;
-    val.attr.zombie = 0;
 }
 
 process::process(const process& parent)
-    : process { parent.pid, parent.is_system() }
+    : process { parent.pid,
+        parent.is_system(),
+        types::string<>(parent.pwd),
+        kernel::signal_list(parent.signals) }
 {
+    this->pgid = parent.pgid;
+    this->sid = parent.sid;
+
     for (auto& area : parent.mms) {
-        if (area.is_ident())
+        if (area.is_kernel_space() || area.attr.in.system)
             continue;
 
         mms.mirror_area(area);
     }
 
-    this->files.dup(parent.files);
+    this->files.dup_all(parent.files);
 }
 
-process::process(pid_t _ppid, bool _system)
+process::process(pid_t _ppid,
+    bool _system,
+    types::string<>&& path,
+    kernel::signal_list&& _sigs)
     : mms(*kernel_mms)
     , attr { .system = _system }
+    , pwd { types::move(path) }
+    , signals(types::move(_sigs))
     , pid { process::alloc_pid() }
     , ppid { _ppid }
+    , pgid { 0 }
+    , sid { 0 }
 {
 }
 
@@ -114,10 +168,33 @@ void proclist::kill(pid_t pid, int exit_code)
     // notify parent process and init
     auto* parent = this->find(proc->ppid);
     auto* init = this->find(1);
-    while (!proc->wait_lst.empty()) {
-        init->wait_lst.push(proc->wait_lst.front());
+
+    bool flag = false;
+    {
+        auto& mtx = init->cv_wait.mtx();
+        types::lock_guard lck(mtx);
+
+        {
+            auto& mtx = proc->cv_wait.mtx();
+            types::lock_guard lck(mtx);
+
+            for (const auto& item : proc->waitlist) {
+                init->waitlist.push_back(item);
+                flag = true;
+            }
+
+            proc->waitlist.clear();
+        }
     }
-    parent->wait_lst.push({ nullptr, (void*)pid, (void*)exit_code, nullptr });
+    if (flag)
+        init->cv_wait.notify();
+
+    {
+        auto& mtx = parent->cv_wait.mtx();
+        types::lock_guard lck(mtx);
+        parent->waitlist.push_back({ pid, exit_code });
+    }
+    parent->cv_wait.notify();
 }
 
 void kernel_threadd_main(void)
@@ -189,18 +266,22 @@ void NORETURN _kernel_init(void)
     hw::init_ata();
 
     // TODO: parse kernel parameters
-    auto* _new_fs = fs::register_fs(types::_new<types::kernel_allocator, fs::fat::fat32>(fs::vfs_open("/dev/hda1")->ind));
-    int ret = fs::fs_root->ind->fs->mount(fs::vfs_open("/mnt"), _new_fs);
+    auto* drive = fs::vfs_open("/dev/hda1");
+    assert(drive);
+    auto* _new_fs = fs::register_fs(new fs::fat::fat32(drive->ind));
+    auto* mnt = fs::vfs_open("/mnt");
+    assert(mnt);
+    int ret = fs::fs_root->ind->fs->mount(mnt, _new_fs);
     assert(ret == GB_OK);
 
     current_process->attr.system = 0;
     current_thread->attr.system = 0;
 
-    const char* argv[] = { "/mnt/INIT.ELF", "/mnt/SH.ELF", nullptr };
+    const char* argv[] = { "/mnt/init", "/mnt/sh", nullptr };
     const char* envp[] = { nullptr };
 
     types::elf::elf32_load_data d;
-    d.exec = "/mnt/INIT.ELF";
+    d.exec = "/mnt/init";
     d.argv = argv;
     d.envp = envp;
     d.system = false;
@@ -238,14 +319,35 @@ void k_new_thread(void (*func)(void*), void* data)
 
 void NORETURN init_scheduler(void)
 {
-    procs = types::pnew<types::kernel_allocator>(procs);
-    readythds = types::pnew<types::kernel_allocator>(readythds);
+    {
+        extern char __stage1_start[];
+        extern char __kinit_end[];
+
+        kernel::paccess pa(EARLY_KERNEL_PD_PAGE);
+        auto pd = (pd_t)pa.ptr();
+        assert(pd);
+        (*pd)[0].v = 0;
+
+        // free pt#0
+        __free_raw_page(0x00002);
+
+        // free .stage1 and .kinit
+        for (uint32_t i = ((uint32_t)__stage1_start >> 12);
+             i < ((uint32_t)__kinit_end >> 12); ++i) {
+            __free_raw_page(i);
+        }
+    }
+
+    procs = new proclist;
+    readythds = new readyqueue;
 
     process::filearr::init_global_file_container();
 
     // init process has no parent
     auto* init = &procs->emplace(0)->value;
-    init->files.open("/dev/console", 0);
+    init->files.open("/dev/console", O_RDONLY);
+    init->files.open("/dev/console", O_WRONLY);
+    init->files.open("/dev/console", O_WRONLY);
 
     // we need interrupts enabled for cow mapping so now we disable it
     // in case timer interrupt mess things up
@@ -256,7 +358,7 @@ void NORETURN init_scheduler(void)
     readythds->push(current_thread);
 
     tss.ss0 = KERNEL_DATA_SEGMENT;
-    tss.esp0 = current_thread->kstack;
+    tss.esp0 = current_thread->pkstack;
 
     asm_switch_pd(current_process->mms.m_pd);
 
@@ -290,25 +392,30 @@ void NORETURN init_scheduler(void)
 }
 
 extern "C" void asm_ctx_switch(uint32_t** curr_esp, uint32_t* next_esp);
-void schedule()
+bool schedule()
 {
     auto thd = readythds->query();
+    process* proc = nullptr;
+    thread* curr_thd = nullptr;
 
     if (current_thread == thd)
-        return;
+        goto _end;
 
-    process* proc = thd->owner;
+    proc = thd->owner;
     if (current_process != proc) {
         asm_switch_pd(proc->mms.m_pd);
         current_process = proc;
     }
 
-    auto* curr_thd = current_thread;
+    curr_thd = current_thread;
 
     current_thread = thd;
-    tss.esp0 = current_thread->kstack;
+    tss.esp0 = current_thread->pkstack;
 
     asm_ctx_switch(&curr_thd->esp, thd->esp);
+
+_end:
+    return current_process->signals.empty();
 }
 
 void NORETURN schedule_noreturn(void)
@@ -330,3 +437,17 @@ void NORETURN kill_current(int exit_code)
     procs->kill(current_process->pid, exit_code);
     schedule_noreturn();
 }
+
+void check_signal()
+{
+    switch (current_process->signals.pop()) {
+    case kernel::SIGINT:
+    case kernel::SIGQUIT:
+    case kernel::SIGPIPE:
+    case kernel::SIGSTOP:
+        kill_current(-1);
+        break;
+    case 0:
+        break;
+    }
+}

+ 0 - 0
src/kernel/signal.cpp


+ 276 - 96
src/kernel/syscall.cpp

@@ -1,6 +1,7 @@
 #include <asm/port_io.h>
 #include <asm/sys.h>
 #include <assert.h>
+#include <bits/ioctl.h>
 #include <kernel/errno.h>
 #include <kernel/interrupt.h>
 #include <kernel/log.hpp>
@@ -10,33 +11,19 @@
 #include <kernel/syscall.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
+#include <string.h>
 #include <types/allocator.hpp>
 #include <types/elf.hpp>
+#include <types/lock.hpp>
 #include <types/status.h>
 
-#define SYSCALL_SET_RETURN_VAL_EAX(_eax) \
-    data->s_regs.eax = ((decltype(data->s_regs.eax))(_eax))
-
-#define SYSCALL_SET_RETURN_VAL_EDX(_edx) \
-    data->s_regs.edx = ((decltype(data->s_regs.edx))(_edx))
-
-#define SYSCALL_SET_RETURN_VAL(_eax, _edx) \
-    SYSCALL_SET_RETURN_VAL_EAX(_eax);      \
-    SYSCALL_SET_RETURN_VAL_EDX(_edx)
-
-#define SYSCALL_HANDLERS_SIZE (16)
+#define SYSCALL_HANDLERS_SIZE (128)
 syscall_handler syscall_handlers[SYSCALL_HANDLERS_SIZE];
 
-void _syscall_not_impl(interrupt_stack* data)
-{
-    SYSCALL_SET_RETURN_VAL(0xffffffff, 0xffffffff);
-}
-
 extern "C" void _syscall_stub_fork_return(void);
-void _syscall_fork(interrupt_stack* data)
+int _syscall_fork(interrupt_stack* data)
 {
     auto* newproc = &procs->emplace(*current_process)->value;
     auto* newthd = &newproc->thds.Emplace(*current_thread, newproc);
@@ -74,65 +61,104 @@ void _syscall_fork(interrupt_stack* data)
     // eflags
     push_stack(&newthd->esp, 0);
 
-    SYSCALL_SET_RETURN_VAL(newproc->pid, 0);
+    return newproc->pid;
 }
 
-void _syscall_write(interrupt_stack* data)
+int _syscall_write(interrupt_stack* data)
 {
     int fd = data->s_regs.edi;
     const char* buf = reinterpret_cast<const char*>(data->s_regs.esi);
     size_t n = data->s_regs.edx;
 
     auto* file = current_process->files[fd];
-    if (file->type == fs::file::types::directory) {
-        SYSCALL_SET_RETURN_VAL(GB_FAILED, EINVAL);
-        return;
-    }
 
-    int n_wrote = fs::vfs_write(file->ind, buf, file->cursor, n);
-    file->cursor += n_wrote;
-    SYSCALL_SET_RETURN_VAL(n_wrote, 0);
+    if (!file || !file->flags.write)
+        return -EBADF;
+
+    switch (file->type) {
+    case fs::file::types::ind: {
+        if (file->ptr.ind->flags.in.directory)
+            return -EBADF;
+
+        int n_wrote = fs::vfs_write(file->ptr.ind, buf, file->cursor, n);
+        if (n_wrote >= 0)
+            file->cursor += n_wrote;
+        return n_wrote;
+    }
+    case fs::file::types::pipe:
+        return file->ptr.pp->write(buf, n);
+
+    case fs::file::types::socket:
+        // TODO
+        return -EINVAL;
+    default:
+        assert(false);
+    }
 }
 
-void _syscall_read(interrupt_stack* data)
+int _syscall_read(interrupt_stack* data)
 {
     int fd = data->s_regs.edi;
     char* buf = reinterpret_cast<char*>(data->s_regs.esi);
     size_t n = data->s_regs.edx;
 
     auto* file = current_process->files[fd];
-    if (file->type == fs::file::types::directory) {
-        SYSCALL_SET_RETURN_VAL(GB_FAILED, EINVAL);
-        return;
-    }
 
-    // TODO: copy to user function !IMPORTANT
-    int n_wrote = fs::vfs_read(file->ind, buf, n, file->cursor, n);
-    file->cursor += n_wrote;
-    SYSCALL_SET_RETURN_VAL(n_wrote, 0);
+    if (!file || !file->flags.read)
+        return -EBADF;
+
+    switch (file->type) {
+    case fs::file::types::ind: {
+        if (file->ptr.ind->flags.in.directory)
+            return -EBADF;
+
+        // TODO: copy to user function !IMPORTANT
+        int n_wrote = fs::vfs_read(file->ptr.ind, buf, n, file->cursor, n);
+        if (n_wrote >= 0)
+            file->cursor += n_wrote;
+        return n_wrote;
+    }
+    case fs::file::types::pipe:
+        return file->ptr.pp->read(buf, n);
+
+    case fs::file::types::socket:
+        // TODO
+        return -EINVAL;
+    default:
+        assert(false);
+    }
 }
 
-void _syscall_sleep(interrupt_stack* data)
+// TODO: sleep seconds
+int _syscall_sleep(interrupt_stack*)
 {
     current_thread->attr.ready = 0;
     current_thread->attr.wait = 1;
 
-    SYSCALL_SET_RETURN_VAL(0, 0);
-
     schedule();
+    return 0;
 }
 
-void _syscall_crash(interrupt_stack*)
+int _syscall_chdir(interrupt_stack* data)
 {
-    kmsg("\nan error occurred while executing command\n");
-    freeze();
+    const char* path = reinterpret_cast<const char*>(data->s_regs.edi);
+    auto* dir = fs::vfs_open(path);
+    if (!dir)
+        return -ENOENT;
+
+    if (!dir->ind->flags.in.directory)
+        return -ENOTDIR;
+
+    current_process->pwd = path;
+
+    return 0;
 }
 
 // syscall_exec(const char* exec, const char** argv)
 // @param exec: the path of program to execute
 // @param argv: arguments end with nullptr
 // @param envp: environment variables end with nullptr
-void _syscall_exec(interrupt_stack* data)
+int _syscall_execve(interrupt_stack* data)
 {
     const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
     char* const* argv = reinterpret_cast<char* const*>(data->s_regs.esi);
@@ -145,89 +171,79 @@ void _syscall_exec(interrupt_stack* data)
     d.system = false;
 
     int ret = types::elf::elf32_load(&d);
-    if (ret != GB_OK) {
-        data->s_regs.eax = d.errcode;
-        return;
-    }
+    if (ret != GB_OK)
+        return -d.errcode;
 
     data->v_eip = d.eip;
     data->esp = (uint32_t)d.sp;
+
+    return 0;
 }
 
 // @param exit_code
-void _syscall_exit(interrupt_stack* data)
+int NORETURN _syscall_exit(interrupt_stack* data)
 {
     uint32_t exit_code = data->s_regs.edi;
 
     // TODO: terminating a thread only
     if (current_thread->owner->thds.size() != 1) {
-        _syscall_crash(data);
+        assert(false);
     }
 
     // terminating a whole process:
     procs->kill(current_process->pid, exit_code);
 
     // switch to new process and continue
-    schedule();
-
-    // we should not return to here
-    assert(false);
+    schedule_noreturn();
 }
 
 // @param address of exit code: int*
 // @return pid of the exited process
-void _syscall_wait(interrupt_stack* data)
+int _syscall_wait(interrupt_stack* data)
 {
     auto* arg1 = reinterpret_cast<int*>(data->s_regs.edi);
 
-    if (arg1 < (int*)0x40000000) {
-        SYSCALL_SET_RETURN_VAL(-1, EINVAL);
-        return;
-    }
-
-    auto& waitlst = current_process->wait_lst;
-    if (waitlst.empty() && !procs->has_child(current_process->pid)) {
-        SYSCALL_SET_RETURN_VAL(-1, ECHILD);
-        return;
-    }
+    auto& cv = current_process->cv_wait;
+    auto& mtx = cv.mtx();
+    types::lock_guard lck(mtx);
 
-    while (waitlst.empty()) {
-        current_thread->attr.ready = 0;
-        current_thread->attr.wait = 1;
-        waitlst.subscribe(current_thread);
+    auto& waitlist = current_process->waitlist;
 
-        schedule();
+    while (waitlist.empty()) {
+        if (!procs->has_child(current_process->pid))
+            return -ECHILD;
 
-        if (!waitlst.empty()) {
-            waitlst.unsubscribe(current_thread);
-            break;
-        }
+        if (!cv.wait(mtx))
+            return -EINTR;
     }
 
-    auto evt = waitlst.front();
+    auto iter = waitlist.begin();
+    assert(iter != waitlist.end());
+
+    auto& obj = *iter;
+    pid_t pid = obj.pid;
 
-    pid_t pid = (pid_t)evt.data1;
     // TODO: copy_to_user check privilege
-    *arg1 = (int)evt.data2;
+    *arg1 = obj.code;
 
     procs->remove(pid);
-    SYSCALL_SET_RETURN_VAL(pid, 0);
+    waitlist.erase(iter);
+
+    return pid;
 }
 
-void _syscall_getdents(interrupt_stack* data)
+int _syscall_getdents(interrupt_stack* data)
 {
     int fd = data->s_regs.edi;
     auto* buf = (char*)(data->s_regs.esi);
     size_t cnt = data->s_regs.edx;
 
     auto* dir = current_process->files[fd];
-    if (dir->type != fs::file::types::directory) {
-        data->s_regs.eax = -1;
-        return;
-    }
+    if (dir->type != fs::file::types::ind || !dir->ptr.ind->flags.in.directory)
+        return -ENOTDIR;
 
     size_t orig_cnt = cnt;
-    int nread = dir->ind->fs->inode_readdir(dir->ind, dir->cursor,
+    int nread = dir->ptr.ind->fs->inode_readdir(dir->ptr.ind, dir->cursor,
         [&buf, &cnt](const char* fn, size_t len, fs::ino_t ino, uint8_t type) -> int {
             if (!len)
                 len = strlen(fn);
@@ -254,27 +270,191 @@ void _syscall_getdents(interrupt_stack* data)
     if (nread > 0)
         dir->cursor += nread;
 
-    data->s_regs.eax = orig_cnt - cnt;
+    return orig_cnt - cnt;
 }
 
-void _syscall_open(interrupt_stack* data)
+int _syscall_open(interrupt_stack* data)
 {
     auto* path = (const char*)data->s_regs.edi;
-    // flags are ignored for now
     uint32_t flags = data->s_regs.esi;
-    data->s_regs.eax = current_process->files.open(path, flags);
+    return current_process->files.open(path, flags);
+}
+
+int _syscall_getcwd(interrupt_stack* data)
+{
+    char* buf = reinterpret_cast<char*>(data->s_regs.edi);
+    size_t bufsize = reinterpret_cast<size_t>(data->s_regs.esi);
+
+    // TODO: use copy_to_user
+    strncpy(buf, current_process->pwd.c_str(), bufsize);
+    buf[bufsize - 1] = 0;
+
+    return (uint32_t)buf;
+}
+
+int _syscall_setsid(interrupt_stack*)
+{
+    if (current_process->pid == current_process->pgid)
+        return -EPERM;
+
+    current_process->sid = current_process->pid;
+    current_process->pgid = current_process->pid;
+
+    // TODO: get tty* from fd or block device id
+    procs->set_ctrl_tty(current_process->pid, console);
+
+    return current_process->pid;
+}
+
+int _syscall_getsid(interrupt_stack* data)
+{
+    pid_t pid = data->s_regs.edi;
+
+    auto* proc = procs->find(pid);
+    if (!proc)
+        return -ESRCH;
+    if (proc->sid != current_process->sid)
+        return -EPERM;
+
+    return proc->sid;
+}
+
+int _syscall_close(interrupt_stack* data)
+{
+    int fd = data->s_regs.edi;
+    current_process->files.close(fd);
+    return 0;
+}
+
+int _syscall_dup(interrupt_stack* data)
+{
+    int old_fd = data->s_regs.edi;
+    return current_process->files.dup(old_fd);
+}
+
+int _syscall_dup2(interrupt_stack* data)
+{
+    int old_fd = data->s_regs.edi;
+    int new_fd = data->s_regs.esi;
+    return current_process->files.dup2(old_fd, new_fd);
+}
+
+int _syscall_pipe(interrupt_stack* data)
+{
+    auto& pipefd = *(int(*)[2])data->s_regs.edi;
+    return current_process->files.pipe(pipefd);
+}
+
+int _syscall_setpgid(interrupt_stack* data)
+{
+    pid_t pid = data->s_regs.edi;
+    pid_t pgid = data->s_regs.esi;
+
+    if (pgid < 0)
+        return -EINVAL;
+
+    if (pid == 0)
+        pid = current_process->pid;
+
+    if (pgid == 0)
+        pgid = pid;
+
+    auto* proc = procs->find(pid);
+    // TODO: check whether the process exists
+    // if (!proc)
+    //     return -ESRCH;
+
+    // TODO: check whether pgid and the original
+    //       pgid is in the same session
+    proc->pgid = pgid;
+
+    return 0;
 }
 
+int _syscall_ioctl(interrupt_stack* data)
+{
+    int fd = data->s_regs.edi;
+    unsigned long request = data->s_regs.esi;
+
+    // TODO: check fd type and get tty* from fd
+    //
+    //       we use a trick for now, check whether
+    //       the file that fd points to is a pipe or
+    //       not. and we suppose that stdin will be
+    //       either a tty or a pipe.
+    auto* file = current_process->files[fd];
+    if (!file || file->type != fs::file::types::ind)
+        return -ENOTTY;
+
+    switch (request) {
+    case TIOCGPGRP: {
+        auto* pgid = (pid_t*)data->s_regs.edx;
+        tty* ctrl_tty = procs->get_ctrl_tty(current_process->pid);
+        // TODO: copy_to_user
+        *pgid = ctrl_tty->get_pgrp();
+        break;
+    }
+    case TIOCSPGRP: {
+        // TODO: copy_from_user
+        pid_t pgid = *(const pid_t*)data->s_regs.edx;
+        tty* ctrl_tty = procs->get_ctrl_tty(current_process->pid);
+        ctrl_tty->set_pgrp(pgid);
+        break;
+    }
+    default:
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int _syscall_getpid(interrupt_stack*)
+{
+    return current_process->pid;
+}
+
+int _syscall_getppid(interrupt_stack*)
+{
+    return current_process->ppid;
+}
+
+extern "C" void syscall_entry(interrupt_stack* data)
+{
+    int syscall_no = data->s_regs.eax;
+    if (syscall_no >= SYSCALL_HANDLERS_SIZE)
+        kill_current(-1);
+
+    int ret = syscall_handlers[syscall_no](data);
+
+    data->s_regs.eax = ret;
+
+    check_signal();
+}
+
+SECTION(".text.kinit")
 void init_syscall(void)
 {
-    syscall_handlers[0] = _syscall_fork;
+    memset(syscall_handlers, 0x00, sizeof(syscall_handlers));
+
+    syscall_handlers[0] = _syscall_read;
     syscall_handlers[1] = _syscall_write;
-    syscall_handlers[2] = _syscall_sleep;
-    syscall_handlers[3] = _syscall_crash;
-    syscall_handlers[4] = _syscall_exec;
-    syscall_handlers[5] = _syscall_exit;
-    syscall_handlers[6] = _syscall_wait;
-    syscall_handlers[7] = _syscall_read;
-    syscall_handlers[8] = _syscall_getdents;
-    syscall_handlers[9] = _syscall_open;
+    syscall_handlers[2] = _syscall_open;
+    syscall_handlers[3] = _syscall_close;
+    syscall_handlers[16] = _syscall_ioctl;
+    syscall_handlers[22] = _syscall_pipe;
+    syscall_handlers[32] = _syscall_dup;
+    syscall_handlers[33] = _syscall_dup2;
+    syscall_handlers[35] = _syscall_sleep;
+    syscall_handlers[39] = _syscall_getpid;
+    syscall_handlers[57] = _syscall_fork;
+    syscall_handlers[59] = _syscall_execve;
+    syscall_handlers[60] = _syscall_exit;
+    syscall_handlers[61] = _syscall_wait;
+    syscall_handlers[78] = _syscall_getdents;
+    syscall_handlers[79] = _syscall_getcwd;
+    syscall_handlers[80] = _syscall_chdir;
+    syscall_handlers[109] = _syscall_setpgid;
+    syscall_handlers[110] = _syscall_getppid;
+    syscall_handlers[112] = _syscall_setsid;
+    syscall_handlers[124] = _syscall_getsid;
 }

+ 50 - 20
src/kernel/tty.cpp

@@ -1,9 +1,11 @@
+#include <kernel/event/evtqueue.hpp>
 #include <kernel/hw/serial.h>
 #include <kernel/process.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vga.hpp>
 #include <stdint.h>
 #include <stdio.h>
+#include <types/lock.hpp>
 
 tty::tty()
     : buf(BUFFER_SIZE)
@@ -21,12 +23,14 @@ size_t tty::read(char* buf, size_t buf_size, size_t n)
     size_t orig_n = n;
 
     while (buf_size && n) {
-        while (this->buf.empty()) {
-            current_thread->attr.ready = 0;
-            current_thread->attr.wait = 1;
-            this->blocklist.subscribe(current_thread);
-            schedule();
-            this->blocklist.unsubscribe(current_thread);
+        auto& mtx = this->m_cv.mtx();
+        types::lock_guard lck(mtx);
+
+        if (this->buf.empty()) {
+            bool intr = !this->m_cv.wait(mtx);
+
+            if (intr || this->buf.empty())
+                break;
         }
 
         *buf = this->buf.get();
@@ -78,33 +82,59 @@ void serial_tty::recvchar(char c)
             serial_send_data(PORT_SERIAL0, '\r');
             serial_send_data(PORT_SERIAL0, '\n');
         }
-        this->blocklist.notify();
+        this->m_cv.notify();
         break;
     // ^?: backspace
     case 0x7f:
-        if (!buf.empty() && buf.back() != '\n')
+        if (!buf.empty() && buf.back() != '\n') {
             buf.pop();
 
-        if (echo) {
-            serial_send_data(PORT_SERIAL0, 0x08);
-            serial_send_data(PORT_SERIAL0, '\x1b');
-            serial_send_data(PORT_SERIAL0, '[');
-            serial_send_data(PORT_SERIAL0, 'K');
+            if (echo) {
+                serial_send_data(PORT_SERIAL0, 0x08);
+                serial_send_data(PORT_SERIAL0, '\x1b');
+                serial_send_data(PORT_SERIAL0, '[');
+                serial_send_data(PORT_SERIAL0, 'K');
+            }
         }
         break;
     // ^U: clear the line
     case 0x15:
-        while (!buf.empty() && buf.back() != '\n')
+        while (!buf.empty() && buf.back() != '\n') {
             buf.pop();
 
-        if (echo) {
-            serial_send_data(PORT_SERIAL0, '\r');
-            serial_send_data(PORT_SERIAL0, '\x1b');
-            serial_send_data(PORT_SERIAL0, '[');
-            serial_send_data(PORT_SERIAL0, '2');
-            serial_send_data(PORT_SERIAL0, 'K');
+            if (echo) {
+                // clear the line
+                // serial_send_data(PORT_SERIAL0, '\r');
+                // serial_send_data(PORT_SERIAL0, '\x1b');
+                // serial_send_data(PORT_SERIAL0, '[');
+                // serial_send_data(PORT_SERIAL0, '2');
+                // serial_send_data(PORT_SERIAL0, 'K');
+                serial_send_data(PORT_SERIAL0, 0x08);
+                serial_send_data(PORT_SERIAL0, '\x1b');
+                serial_send_data(PORT_SERIAL0, '[');
+                serial_send_data(PORT_SERIAL0, 'K');
+            }
         }
         break;
+    // ^C: SIGINT
+    case 0x03:
+        procs->send_signal_grp(fg_pgroup, kernel::SIGINT);
+        this->m_cv.notify();
+        break;
+    // ^D: EOF
+    case 0x04:
+        this->m_cv.notify();
+        break;
+    // ^Z: SIGSTOP
+    case 0x1a:
+        procs->send_signal_grp(fg_pgroup, kernel::SIGSTOP);
+        this->m_cv.notify();
+        break;
+    // ^\: SIGQUIT
+    case 0x1c:
+        procs->send_signal_grp(fg_pgroup, kernel::SIGQUIT);
+        this->m_cv.notify();
+        break;
     default:
         buf.put(c);
         if (echo)

+ 103 - 3
src/kernel/vfs.cpp

@@ -1,6 +1,7 @@
 #include <assert.h>
 #include <kernel/errno.h>
 #include <kernel/mem.h>
+#include <kernel/process.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
 #include <stdint.h>
@@ -53,8 +54,10 @@ fs::vfs::dentry::dentry(dentry&& val)
     , flags { val.flags }
     , name(types::move(val.name))
 {
-    for (auto& item : *children)
-        item.parent = this;
+    if (children) {
+        for (auto& item : *children)
+            item.parent = this;
+    }
     memset(&val, 0x00, sizeof(dentry));
 }
 fs::vfs::dentry::~dentry()
@@ -82,6 +85,9 @@ fs::vfs::dentry* fs::vfs::dentry::append(inode* ind, name_type&& name, bool set_
 }
 fs::vfs::dentry* fs::vfs::dentry::find(const name_type& name)
 {
+    if (!ind->flags.in.directory)
+        return nullptr;
+
     if (ind->flags.in.directory && !flags.in.present)
         ind->fs->load_dentry(this);
 
@@ -530,6 +536,8 @@ fs::vfs::dentry* fs::vfs_open(const char* path)
 int fs::vfs_stat(const char* filename, stat* stat)
 {
     auto ent = vfs_open(filename);
+    if (!ent)
+        return GB_FAILED;
     return vfs_stat(ent, stat);
 }
 int fs::vfs_stat(fs::vfs::dentry* ent, stat* stat)
@@ -584,6 +592,98 @@ static size_t console_write(fs::special_node*, const char* buf, size_t, size_t n
     return orig_n;
 }
 
+fs::pipe::pipe(void)
+    : buf { PIPE_SIZE }
+    , flags { READABLE | WRITABLE }
+{
+}
+
+void fs::pipe::close_read(void)
+{
+    {
+        types::lock_guard lck(m_cv.mtx());
+        flags &= (~READABLE);
+    }
+    m_cv.notify_all();
+}
+
+void fs::pipe::close_write(void)
+{
+    {
+        types::lock_guard lck(m_cv.mtx());
+        flags &= (~WRITABLE);
+    }
+    m_cv.notify_all();
+}
+
+int fs::pipe::write(const char* buf, size_t n)
+{
+    // TODO: check privilege
+    // TODO: check EPIPE
+    {
+        auto& mtx = m_cv.mtx();
+        types::lock_guard lck(mtx);
+
+        if (!is_readable()) {
+            current_process->signals.set(kernel::SIGPIPE);
+            return -EPIPE;
+        }
+
+        while (this->buf.avail() < n) {
+            if (!m_cv.wait(mtx))
+                return -EINTR;
+
+            if (!is_readable()) {
+                current_process->signals.set(kernel::SIGPIPE);
+                return -EPIPE;
+            }
+        }
+
+        for (size_t i = 0; i < n; ++i)
+            this->buf.put(*(buf++));
+    }
+
+    m_cv.notify();
+    return n;
+}
+
+int fs::pipe::read(char* buf, size_t n)
+{
+    // TODO: check privilege
+    {
+        auto& mtx = m_cv.mtx();
+        types::lock_guard lck(mtx);
+
+        if (!is_writeable()) {
+            size_t orig_n = n;
+            while (!this->buf.empty() && n--)
+                *(buf++) = this->buf.get();
+
+            return orig_n - n;
+        }
+
+        while (this->buf.size() < n) {
+            if (!m_cv.wait(mtx))
+                return -EINTR;
+
+            if (!is_writeable()) {
+                size_t orig_n = n;
+                while (!this->buf.empty() && n--)
+                    *(buf++) = this->buf.get();
+
+                return orig_n - n;
+            }
+        }
+
+        for (size_t i = 0; i < n; ++i)
+            *(buf++) = this->buf.get();
+    }
+
+    m_cv.notify();
+    return n;
+}
+
+SECTION(".text.kinit")
 void init_vfs(void)
 {
     using namespace fs;
@@ -595,7 +695,7 @@ void init_vfs(void)
 
     fs_es = types::pnew<types::kernel_ident_allocator>(fs_es);
 
-    auto* rootfs = types::_new<types::kernel_allocator, tmpfs>();
+    auto* rootfs = new tmpfs;
     fs_es->push_back(rootfs);
     fs_root = rootfs->root();
 

+ 0 - 185
src/kernel_main.cpp

@@ -1,185 +0,0 @@
-#include "kernel_main.hpp"
-
-#include <asm/boot.h>
-#include <asm/port_io.h>
-#include <asm/sys.h>
-#include <assert.h>
-#include <kernel/event/event.h>
-#include <kernel/hw/keyboard.h>
-#include <kernel/hw/serial.h>
-#include <kernel/hw/timer.h>
-#include <kernel/interrupt.h>
-#include <kernel/log.hpp>
-#include <kernel/mem.h>
-#include <kernel/process.hpp>
-#include <kernel/task.h>
-#include <kernel/tty.hpp>
-#include <kernel/vga.hpp>
-#include <stdint.h>
-#include <stdio.h>
-#include <types/bitmap.h>
-#include <types/status.h>
-#include <types/types.h>
-
-#define KERNEL_MAIN_BUF_SIZE (128)
-
-#define printkf(x...)                       \
-    snprintf(buf, KERNEL_MAIN_BUF_SIZE, x); \
-    console->print(buf)
-
-typedef void (*constructor)(void);
-extern constructor start_ctors;
-extern constructor end_ctors;
-void call_constructors_for_cpp(void)
-{
-    for (constructor* ctor = &start_ctors; ctor != &end_ctors; ++ctor) {
-        (*ctor)();
-    }
-}
-
-uint8_t e820_mem_map[1024];
-uint32_t e820_mem_map_count;
-uint32_t e820_mem_map_entry_size;
-size_t kernel_size;
-struct mem_size_info mem_size_info;
-
-static inline void save_loader_data(void)
-{
-    memcpy(e820_mem_map, asm_e820_mem_map, sizeof(e820_mem_map));
-    e820_mem_map_count = asm_e820_mem_map_count;
-    e820_mem_map_entry_size = asm_e820_mem_map_entry_size;
-    kernel_size = asm_kernel_size;
-    memcpy(&mem_size_info, &asm_mem_size_info, sizeof(struct mem_size_info));
-}
-
-static inline void show_mem_info(char* buf)
-{
-    uint32_t mem_size = 0;
-    mem_size += 1024 * mem_size_info.n_1k_blks;
-    mem_size += 64 * 1024 * mem_size_info.n_64k_blks;
-
-    printkf(
-        "Memory size: %d bytes (%d MB), 16k blocks: %d, 64k blocks: %d\n",
-        mem_size,
-        mem_size / 1024 / 1024,
-        (int32_t)mem_size_info.n_1k_blks,
-        (int32_t)mem_size_info.n_64k_blks);
-
-    printkf(
-        "mem_map_entry_count: %d , mem_map_entry_size: %d \n",
-        e820_mem_map_count,
-        e820_mem_map_entry_size);
-
-    if (e820_mem_map_entry_size == 20) {
-        struct e820_mem_map_entry_20* entry = (struct e820_mem_map_entry_20*)e820_mem_map;
-        for (uint32_t i = 0; i < e820_mem_map_count; ++i, ++entry) {
-            printkf(
-                "[mem] entry %d: %llx ~ %llx, type: %d\n",
-                i,
-                entry->base,
-                entry->base + entry->len,
-                entry->type);
-        }
-    } else {
-        struct e820_mem_map_entry_24* entry = (struct e820_mem_map_entry_24*)e820_mem_map;
-        for (uint32_t i = 0; i < e820_mem_map_count; ++i, ++entry) {
-            printkf(
-                "[mem] entry %d: %lld ~ %lld, type: %d, acpi_attr: %d\n",
-                i,
-                entry->in.base,
-                entry->in.base + entry->in.len,
-                entry->in.type,
-                entry->acpi_extension_attr);
-        }
-    }
-    printkf("kernel size: %x\n", kernel_size);
-}
-
-static segment_descriptor new_gdt[6];
-struct tss32_t tss;
-
-void load_new_gdt(void)
-{
-    create_segment_descriptor(new_gdt + 0, 0, 0, 0, 0);
-    create_segment_descriptor(new_gdt + 1, 0, ~0, 0b1100, SD_TYPE_CODE_SYSTEM);
-    create_segment_descriptor(new_gdt + 2, 0, ~0, 0b1100, SD_TYPE_DATA_SYSTEM);
-    create_segment_descriptor(new_gdt + 3, 0, ~0, 0b1100, SD_TYPE_CODE_USER);
-    create_segment_descriptor(new_gdt + 4, 0, ~0, 0b1100, SD_TYPE_DATA_USER);
-    create_segment_descriptor(new_gdt + 5, (uint32_t)&tss, sizeof(tss), 0b0000, SD_TYPE_TSS);
-
-    asm_load_gdt((6 * 8 - 1) << 16, (pptr_t)new_gdt);
-    asm_load_tr((6 - 1) * 8);
-
-    asm_cli();
-}
-
-void init_bss_section(void)
-{
-    void* bss_addr = (void*)bss_section_start_addr;
-    size_t bss_size = bss_section_end_addr - bss_section_start_addr;
-    memset(bss_addr, 0x00, bss_size);
-}
-
-int init_console(const char* name)
-{
-    if (name[0] == 't' && name[1] == 't' && name[2] == 'y') {
-        if (name[3] == 'S' || name[3] == 's') {
-            if (name[4] == '0') {
-                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL0);
-                return GB_OK;
-            }
-            if (name[4] == '1') {
-                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL1);
-                return GB_OK;
-            }
-        }
-        if (name[3] == 'V' && name[3] == 'G' && name[3] == 'A') {
-            console = types::_new<types::kernel_ident_allocator, vga_tty>();
-            return GB_OK;
-        }
-    }
-    return GB_FAILED;
-}
-
-extern void init_vfs();
-extern "C" uint32_t check_a20_on(void);
-
-extern "C" void NORETURN kernel_main(void)
-{
-    int ret;
-    ret = check_a20_on();
-    assert(ret == 1);
-
-    asm_enable_sse();
-
-    init_bss_section();
-
-    save_loader_data();
-
-    load_new_gdt();
-
-    // NOTE:
-    // the initializer of c++ global objects MUST NOT contain
-    // all kinds of memory allocations
-    call_constructors_for_cpp();
-
-    char buf[KERNEL_MAIN_BUF_SIZE] = { 0 };
-
-    ret = init_serial_port(PORT_SERIAL0);
-    assert(ret == GB_OK);
-
-    init_idt();
-    init_mem();
-    init_pic();
-    init_pit();
-
-    ret = init_console("ttyS0");
-    assert(ret == GB_OK);
-
-    show_mem_info(buf);
-
-    init_vfs();
-
-    kmsg("switching execution to the scheduler...\n");
-    init_scheduler();
-}

+ 120 - 0
src/kinit.cpp

@@ -0,0 +1,120 @@
+#include <asm/port_io.h>
+#include <asm/sys.h>
+#include <assert.h>
+#include <kernel/event/event.h>
+#include <kernel/hw/keyboard.h>
+#include <kernel/hw/serial.h>
+#include <kernel/hw/timer.h>
+#include <kernel/interrupt.h>
+#include <kernel/log.hpp>
+#include <kernel/mem.h>
+#include <kernel/process.hpp>
+#include <kernel/syscall.hpp>
+#include <kernel/task.h>
+#include <kernel/tty.hpp>
+#include <kernel/vga.hpp>
+#include <stdint.h>
+#include <stdio.h>
+#include <types/bitmap.h>
+#include <types/status.h>
+#include <types/types.h>
+
+typedef void (*constructor)(void);
+extern constructor const SECTION(".rodata.kinit") start_ctors;
+extern constructor const SECTION(".rodata.kinit") end_ctors;
+
+extern struct mem_size_info SECTION(".stage1") asm_mem_size_info;
+extern uint8_t SECTION(".stage1") asm_e820_mem_map[1024];
+extern uint32_t SECTION(".stage1") asm_e820_mem_map_count;
+extern uint32_t SECTION(".stage1") asm_e820_mem_map_entry_size;
+
+SECTION(".text.kinit")
+static inline void save_loader_data(void)
+{
+    memcpy(e820_mem_map, asm_e820_mem_map, sizeof(e820_mem_map));
+    e820_mem_map_count = asm_e820_mem_map_count;
+    e820_mem_map_entry_size = asm_e820_mem_map_entry_size;
+    memcpy(&mem_size_info, &asm_mem_size_info, sizeof(struct mem_size_info));
+}
+
+SECTION(".text.kinit")
+static inline void load_new_gdt(void)
+{
+    create_segment_descriptor(gdt + 0, 0, 0, 0, 0);
+    create_segment_descriptor(gdt + 1, 0, ~0, 0b1100, SD_TYPE_CODE_SYSTEM);
+    create_segment_descriptor(gdt + 2, 0, ~0, 0b1100, SD_TYPE_DATA_SYSTEM);
+    create_segment_descriptor(gdt + 3, 0, ~0, 0b1100, SD_TYPE_CODE_USER);
+    create_segment_descriptor(gdt + 4, 0, ~0, 0b1100, SD_TYPE_DATA_USER);
+    create_segment_descriptor(gdt + 5, (uint32_t)&tss, sizeof(tss), 0b0000, SD_TYPE_TSS);
+
+    asm_load_gdt((6 * 8 - 1) << 16, (pptr_t)gdt);
+    asm_load_tr((6 - 1) * 8);
+
+    asm_cli();
+}
+
+SECTION(".text.kinit")
+static inline void init_bss_section(void)
+{
+    memset(bss_addr, 0x00, bss_len);
+}
+
+SECTION(".text.kinit")
+static inline int init_console(const char* name)
+{
+    if (name[0] == 't' && name[1] == 't' && name[2] == 'y') {
+        if (name[3] == 'S' || name[3] == 's') {
+            if (name[4] == '0') {
+                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL0);
+                return GB_OK;
+            }
+            if (name[4] == '1') {
+                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL1);
+                return GB_OK;
+            }
+        }
+        if (name[3] == 'V' && name[3] == 'G' && name[3] == 'A') {
+            console = types::_new<types::kernel_ident_allocator, vga_tty>();
+            return GB_OK;
+        }
+    }
+    return GB_FAILED;
+}
+
+extern void init_vfs();
+
+extern "C" SECTION(".text.kinit") void NORETURN kernel_init(void)
+{
+    asm_enable_sse();
+
+    init_bss_section();
+
+    save_loader_data();
+
+    load_new_gdt();
+
+    // call global ctors
+    // NOTE:
+    // the initializer of global objects MUST NOT contain
+    // all kinds of memory allocations
+    for (const constructor* ctor = &start_ctors; ctor != &end_ctors; ++ctor) {
+        (*ctor)();
+    }
+
+    int ret = init_serial_port(PORT_SERIAL0);
+    assert(ret == GB_OK);
+
+    init_idt();
+    init_mem();
+    init_pic();
+    init_pit();
+
+    ret = init_console("ttyS0");
+    assert(ret == GB_OK);
+
+    init_vfs();
+    init_syscall();
+
+    kmsg("switching execution to the scheduler...\n");
+    init_scheduler();
+}

+ 2 - 2
src/mbr.S

@@ -26,7 +26,7 @@ mbr_start:
     call read_data
 
 # loader start
-    jmp 0x7e00
+    jmp 0x8000
 
 read_data:
     movw $read_data_pack, %si
@@ -48,7 +48,7 @@ read_data_count:
 read_data_offset:
     .word 0x0000 # offset address
 read_data_segment:
-    .word 0x07e0 # segment address
+    .word 0x0800 # segment address
 read_data_lba:
     .long 1      # lower 4 bytes of the LBA to read
     .long 0      # higher 2 bytes of the LBA to read

+ 3 - 3
src/types/bitmap.c

@@ -7,16 +7,16 @@ size_t make_bm_size(size_t n)
     return sizeof(size_t) + (n / SZ) + ((n % SZ) ? 1 : 0);
 }
 
-int bm_test(char* bm, size_t n)
+int bm_test(uint8_t* bm, size_t n)
 {
     return (bm[n / SZ] & (1 << (n % SZ))) != 0;
 }
 
-void bm_set(char* bm, size_t n)
+void bm_set(uint8_t* bm, size_t n)
 {
     bm[n / SZ] |= (1 << (n % SZ));
 }
-void bm_clear(char* bm, size_t n)
+void bm_clear(uint8_t* bm, size_t n)
 {
     bm[n / SZ] &= (~(1 << (n % SZ)));
 }

+ 56 - 13
src/types/elf.cpp

@@ -49,7 +49,8 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     }
 
     size_t phents_size = hdr.phentsize * hdr.phnum;
-    auto* phents = (types::elf::elf32_program_header_entry*)k_malloc(phents_size);
+    size_t shents_size = hdr.shentsize * hdr.shnum;
+    auto* phents = new types::elf::elf32_program_header_entry[hdr.phnum];
     n_read = fs::vfs_read(
         ent_exec->ind,
         (char*)phents,
@@ -58,7 +59,23 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
 
     // broken file or I/O error
     if (n_read != phents_size) {
-        k_free(phents);
+        delete[] phents;
+
+        d->errcode = EINVAL;
+        return GB_FAILED;
+    }
+
+    auto* shents = new types::elf::elf32_section_header_entry[hdr.shnum];
+    n_read = fs::vfs_read(
+        ent_exec->ind,
+        (char*)shents,
+        shents_size,
+        hdr.shoff, shents_size);
+
+    // broken file or I/O error
+    if (n_read != shents_size) {
+        delete[] phents;
+        delete[] shents;
 
         d->errcode = EINVAL;
         return GB_FAILED;
@@ -75,27 +92,43 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     // so we can't just simply return to it on error.
     current_process->mms.clear_user();
 
+    fs::inode* null_ind = nullptr;
+    {
+        auto* dent = fs::vfs_open("/dev/null");
+        if (!dent) {
+            delete[] phents;
+            delete[] shents;
+            kill_current(-1);
+        }
+        null_ind = dent->ind;
+    }
+
     for (int i = 0; i < hdr.phnum; ++i) {
         if (phents[i].type != types::elf::elf32_program_header_entry::PT_LOAD)
             continue;
 
+        auto vaddr = align_down<12>(phents[i].vaddr);
+        auto vlen = align_up<12>(phents[i].vaddr + phents[i].memsz) - vaddr;
+        auto flen = align_up<12>(phents[i].vaddr + phents[i].filesz) - vaddr;
+        auto fileoff = align_down<12>(phents[i].offset);
+
         auto ret = mmap(
-            (char*)phents[i].vaddr,
-            phents[i].filesz,
+            (char*)vaddr,
+            phents[i].filesz + (phents[i].vaddr & 0xfff),
             ent_exec->ind,
-            phents[i].offset,
+            fileoff,
             1,
             d->system);
 
         if (ret != GB_OK)
             goto error;
 
-        if (phents[i].memsz > align_up<12>(phents[i].filesz)) {
+        if (vlen > flen) {
             ret = mmap(
-                (char*)phents[i].vaddr + align_up<12>(phents[i].filesz),
-                align_up<12>(phents[i].memsz) - align_up<12>(phents[i].filesz),
-                fs::vfs_open("/dev/null")->ind,
-                phents[i].offset + align_up<12>(phents[i].filesz),
+                (char*)vaddr + flen,
+                vlen - flen,
+                null_ind,
+                0,
                 1,
                 d->system);
 
@@ -106,13 +139,20 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
         continue;
 
     error:
-        k_free(phents);
+        delete[] phents;
+        delete[] shents;
         kill_current(-1);
     }
 
+    for (int i = 0; i < hdr.shnum; ++i) {
+        if (shents[i].sh_type == elf32_section_header_entry::SHT_NOBITS)
+            memset((char*)shents[i].sh_addr, 0x00, shents[i].sh_size);
+    }
+
     // map stack area
-    auto ret = mmap((void*)types::elf::ELF_STACK_TOP, types::elf::ELF_STACK_SIZE,
-        fs::vfs_open("/dev/null")->ind, 0, 1, 0);
+    auto ret = mmap((void*)types::elf::ELF_STACK_TOP,
+        types::elf::ELF_STACK_SIZE,
+        null_ind, 0, 1, 0);
     assert(ret == GB_OK);
 
     d->eip = (void*)hdr.entry;
@@ -152,5 +192,8 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     // push argc
     _user_push(sp, args.size());
 
+    delete[] phents;
+    delete[] shents;
+
     return GB_OK;
 }

+ 0 - 9
src/types/libstdcpp.cpp

@@ -5,15 +5,6 @@
 #include <stdio.h>
 #include <types/types.h>
 
-void operator delete(void*)
-{
-    assert(false);
-}
-void operator delete(void*, unsigned int)
-{
-    assert(false);
-}
-
 extern "C" void NORETURN __stack_chk_fail(void)
 {
     assert(false);

+ 4 - 4
user-space-program/CMakeLists.txt

@@ -1,12 +1,10 @@
 cmake_minimum_required(VERSION 3.15)
 project(user_space_program C ASM)
 
-set(CMAKE_C_FLAGS "-nostdinc -nostdlib -static -m32 -W -Wall -Wextra -Werror -mstack-protector-guard=global")
-set(CMAKE_ASM_FLAGS "-m32 -static -mstack-protector-guard=global -g0")
+set(CMAKE_C_FLAGS "-nostdlib -nostdinc -static -m32 -W -Wall -Wextra -Werror -mstack-protector-guard=global")
+set(CMAKE_ASM_FLAGS "-nostdlib -m32 -static -mstack-protector-guard=global -g0")
 
 link_libraries(gblibc)
-add_link_options(-nostdlib -T ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
-# set(LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
 
 set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "")
 set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "")
@@ -17,7 +15,9 @@ add_executable(stack-test.out stack-test.s)
 add_executable(init.out init.c)
 add_executable(sh.out sh.c)
 add_executable(priv-test.out priv-test.c)
+add_executable(lazybox.out lazybox.c)
 
 add_custom_target(user_space_programs
     DEPENDS hello-world.out interrupt-test.out stack-test.out init.out sh.out priv-test.out
+    DEPENDS lazybox.out
 )

+ 2 - 2
user-space-program/hello-world.s

@@ -7,8 +7,8 @@ main:
 	movl $0xcbcbcbcb, %eax
 	movl $0xacacacac, %edx
 
-	movl $0x01, %eax
-	movl $0, %edi
+	movl $1, %eax
+	movl $1, %edi
 	movl $_str, %esi
 	movl $_str_size, %ecx
 	movl (%ecx), %edx

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

@@ -1,14 +1,25 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/wait.h>
 
 #define print(str) write(STDERR_FILENO, str, strlen(str))
 
 int main(int argc, char** argv)
 {
+    int fd = 0;
+    // Assumes three file descriptors open.
+    while((fd = open("/dev/console", 0)) >= 0){
+        if(fd >= 3){
+            close(fd);
+            break;
+        }
+    }
+
     print("***** GBOS INIT SYSTEM *****\n");
 
+_run_sh:;
     pid_t sh_pid = fork();
     if (sh_pid < 0) {
         print("[init] unable to fork(), exiting...\n");
@@ -17,6 +28,12 @@ int main(int argc, char** argv)
 
     // child
     if (sh_pid == 0) {
+        pid_t sid = setsid();
+        if (sid < 0) {
+            print("[init] unable to setsid, exiting...\n");
+            return -1;
+        }
+
         char* shell_argv[128] = {};
         char* envp[1] = { NULL };
 
@@ -40,6 +57,9 @@ int main(int argc, char** argv)
         pid = wait(&ret);
         snprintf(buf, sizeof(buf), "[init] pid%d has exited with code %d\n", pid, ret);
         print(buf);
+        // sh
+        if (pid == sh_pid)
+            goto _run_sh;
     }
 
     return 0;

+ 3 - 3
user-space-program/interrupt-test.s

@@ -5,16 +5,16 @@
 .globl main
 main:
 # fork 1 -> 2
-	xorl %eax, %eax
+	movl $57, %eax
 	int $0x80
 	movl %eax, %esi
 # fork 2 -> 4
-	xorl %eax, %eax
+	movl $57, %eax
 	int $0x80
 	movl %eax, %ecx
 # write
 	movl $1, %eax
-	movl $0, %edi
+	movl $1, %edi
 	movl $__user_interrupt_test_string, %esi
 	movl $(__user_interrupt_test_string_end - __user_interrupt_test_string), %edx
 	int $0x80

+ 168 - 0
user-space-program/lazybox.c

@@ -0,0 +1,168 @@
+#include <unistd.h>
+#include <dirent.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+struct applet {
+    const char* name;
+    int (*func)(const char** args);
+};
+
+int putchar(int c)
+{
+    write(STDOUT_FILENO, &c, 1);
+    return c;
+}
+
+int puts(const char* str)
+{
+    size_t ret = write(STDOUT_FILENO, str, strlen(str));
+    ret += write(STDOUT_FILENO, "\n", 1);
+    return ret;
+}
+
+int printf(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+
+    char buf[128];
+    int n = vsnprintf(buf, sizeof(buf), fmt, args);
+    n = write(STDOUT_FILENO, buf, n);
+
+    va_end(args);
+    return n;
+}
+
+int lazybox_version(const char** _)
+{
+    (void)_;
+    printf("lazybox by greatbridf\n");
+    return 0;
+}
+
+int pwd(const char** _)
+{
+    (void)_;
+    char buf[256];
+    if (getcwd(buf, sizeof(buf)) == 0) {
+        printf("cannot get cwd\n");
+        return -1;
+    }
+    puts(buf);
+    return 0;
+}
+
+int ls(const char** args)
+{
+    const char* path = args[0];
+    DIR* dir = NULL;
+
+    if (path == NULL) {
+        char buf[256];
+        if (getcwd(buf, sizeof(buf)) == 0)
+            return -1;
+
+        dir = opendir(buf);
+    } else {
+        dir = opendir(args[0]);
+    }
+
+    if (!dir)
+        return -1;
+
+    struct dirent* dp = NULL;
+    while ((dp = readdir(dir)) != NULL) {
+        printf("%s ", dp->d_name);
+    }
+
+    printf("\n");
+
+    return 0;
+}
+
+struct applet applets[] = {
+    {
+        "lazybox",
+        lazybox_version,
+    },
+    {
+        "pwd",
+        pwd,
+    },
+    {
+        "ls",
+        ls,
+    }
+};
+
+static inline int tolower(int c)
+{
+    if (c >= 'A' && c <= 'Z')
+        return c - 'A' + 'a';
+    return c;
+}
+
+int strcmpi(const char* a, const char* b)
+{
+    int ret = 0;
+    while (*a && *b) {
+        if (tolower(*a) != tolower(*b)) {
+            ret = 1;
+            break;
+        }
+        ++a, ++b;
+    }
+    if ((*a && !*b) || (*b && !*a)) {
+        ret = 1;
+    }
+    return ret;
+}
+
+const char* find_file_name(const char* path)
+{
+    const char* last = path + strlen(path);
+    for (; last != path; --last) {
+        if (*last == '/')
+            break;
+    }
+    return last + 1;
+}
+
+int parse_applet(const char* name)
+{
+    if (!name)
+        return -1;
+
+    for (size_t i = 0; i < (sizeof(applets) / sizeof(struct applet)); ++i) {
+        if (strcmpi(applets[i].name, name) == 0) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+int main(int argc, const char** argv)
+{
+    (void)argc;
+    int offset = 0;
+    const char* name = find_file_name(argv[offset++]);
+    int type = -1;
+
+run:
+    type = parse_applet(name);
+    if (type == -1) {
+        printf("applet not found: %s\n", name);
+        return -1;
+    }
+
+    if (type == 0 && offset == 1) {
+        name = argv[offset++];
+        goto run;
+    }
+
+    return applets[type].func(argv + offset);
+}

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

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

+ 66 - 62
user-space-program/sh.c

@@ -12,7 +12,7 @@ int printf(const char* fmt, ...)
     va_start(args, fmt);
 
     char buf[256] = {};
-    int len = snprintf(buf, sizeof(buf), fmt, args);
+    int len = vsnprintf(buf, sizeof(buf), fmt, args);
 
     len = write(STDOUT_FILENO, buf, len);
 
@@ -35,9 +35,12 @@ char* strchr(const char* str, int c)
 char* gets(char* buf, int bufsize)
 {
     int n = read(STDIN_FILENO, buf, bufsize);
-    if (n > 0 && buf[n-1] == '\n') {
+    if (n > 0) {
+      if (buf[n-1] == '\n')
         buf[n-1] = 0;
-        return buf;
+      else
+        buf[n] = 0;
+      return buf;
     }
     return NULL;
 }
@@ -52,11 +55,7 @@ int puts(const char* str)
 void* malloc(size_t n)
 {
     static char mems[1024];
-    static int pos = 0;
-    if (n == 0) {
-        pos = 0;
-        return 0;
-    }
+    static int pos;
     int orig_pos = pos;
     pos += n;
     return mems + orig_pos;
@@ -115,12 +114,13 @@ struct cmd *parsecmd(char*);
 void
 runcmd(struct cmd *cmd)
 {
-//   int p[2];
+  int p[2];
+  int code;
   struct backcmd *bcmd;
   struct execcmd *ecmd;
   struct listcmd *lcmd;
-//   struct pipecmd *pcmd;
-//   struct redircmd *rcmd;
+  struct pipecmd *pcmd;
+  struct redircmd *rcmd;
 
   if(cmd == 0)
     _exit(-1);
@@ -138,48 +138,47 @@ runcmd(struct cmd *cmd)
     printf("exec %s failed\n", ecmd->argv[0]);
     break;
 
-//   case REDIR:
-//     rcmd = (struct redircmd*)cmd;
-//     close(rcmd->fd);
-//     if(open(rcmd->file, rcmd->mode) < 0){
-//       printf("open %s failed\n", rcmd->file);
-//       _exit(-1);
-//     }
-//     runcmd(rcmd->cmd);
-//     break;
+  case REDIR:
+    rcmd = (struct redircmd*)cmd;
+    close(rcmd->fd);
+    if(open(rcmd->file, rcmd->mode) < 0){
+      printf("open %s failed\n", rcmd->file);
+      _exit(-1);
+    }
+    runcmd(rcmd->cmd);
+    break;
 
   case LIST:
     lcmd = (struct listcmd*)cmd;
     if(fork1() == 0)
       runcmd(lcmd->left);
-    int code;
     wait(&code);
     runcmd(lcmd->right);
     break;
 
-//   case PIPE:
-//     pcmd = (struct pipecmd*)cmd;
-//     if(pipe(p) < 0)
-//       panic("pipe");
-//     if(fork1() == 0){
-//       close(1);
-//       dup(p[1]);
-//       close(p[0]);
-//       close(p[1]);
-//       runcmd(pcmd->left);
-//     }
-//     if(fork1() == 0){
-//       close(0);
-//       dup(p[0]);
-//       close(p[0]);
-//       close(p[1]);
-//       runcmd(pcmd->right);
-//     }
-//     close(p[0]);
-//     close(p[1]);
-//     wait();
-//     wait();
-//     break;
+   case PIPE:
+     pcmd = (struct pipecmd*)cmd;
+     if(pipe(p) < 0)
+       panic("pipe");
+     if(fork1() == 0){
+       close(1);
+       dup(p[1]);
+       close(p[0]);
+       close(p[1]);
+       runcmd(pcmd->left);
+     }
+     if(fork1() == 0){
+       close(0);
+       dup(p[0]);
+       close(p[0]);
+       close(p[1]);
+       runcmd(pcmd->right);
+     }
+     close(p[0]);
+     close(p[1]);
+     wait(&code);
+     wait(&code);
+     break;
     
   case BACK:
     bcmd = (struct backcmd*)cmd;
@@ -204,32 +203,37 @@ getcmd(char *buf, int nbuf)
 int
 main(void)
 {
-  void* _ = malloc(0);
-  (void)_;
   static char buf[100];
   
-//   // Assumes three file descriptors open.
-//   while((fd = open("console", 0)) >= 0){
-//     if(fd >= 3){
-//       close(fd);
-//       break;
-//     }
-//   }
+  int fd = 0;
+  // Assumes three file descriptors open.
+  while((fd = open("/dev/console", 0)) >= 0){
+    if(fd >= 3){
+      close(fd);
+      break;
+    }
+  }
   
   // Read and run input commands.
   while(getcmd(buf, sizeof(buf)) >= 0){
-    // if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
-    //   // Clumsy but will have to do for now.
-    //   // Chdir has no effect on the parent if run in the child.
-    //   buf[strlen(buf)-1] = 0;  // chop \n
-    //   if(chdir(buf+3) < 0)
-    //     printf("cannot cd %s\n", buf+3);
-    //   continue;
-    // }
-    if(fork1() == 0)
+    if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ')
+    {
+      // Clumsy but will have to do for now.
+      // Chdir has no effect on the parent if run in the child.
+      if(chdir(buf+3) < 0)
+        printf("cannot cd %s\n", buf+3);
+      continue;
+    }
+    pid_t pid = 0;
+    if((pid = fork1()) == 0) {
+      setpgid(0, 0);
       runcmd(parsecmd(buf));
+    }
+    tcsetpgrp(STDOUT_FILENO, pid);
+    setpgid(pid, 0);
     int code;
     wait(&code);
+    tcsetpgrp(STDOUT_FILENO, getpid());
   }
   _exit(0);
 }