Quellcode durchsuchen

Merge branch 'libc'

greatbridf vor 2 Jahren
Ursprung
Commit
2106a9dbaf
60 geänderte Dateien mit 808 neuen und 531 gelöschten Zeilen
  1. 31 54
      CMakeLists.txt
  2. 20 0
      gblibc/CMakeLists.txt
  3. 16 0
      gblibc/include/fcntl.h
  4. 11 0
      gblibc/include/stdarg.h
  5. 7 3
      gblibc/include/stdint.h
  6. 19 0
      gblibc/include/stdio.h
  7. 10 23
      gblibc/include/string.h
  8. 16 0
      gblibc/include/sys/types.h
  9. 16 0
      gblibc/include/sys/wait.h
  10. 23 0
      gblibc/include/unistd.h
  11. 11 0
      gblibc/private-include/devutil.h
  12. 76 0
      gblibc/private-include/syscall.h
  13. 53 0
      gblibc/src/arithmetic.c
  14. 27 0
      gblibc/src/crt0.s
  15. 7 0
      gblibc/src/fcntl.c
  16. 27 165
      gblibc/src/stdio.c
  17. 66 0
      gblibc/src/string.c
  18. 34 0
      gblibc/src/unistd.c
  19. 7 0
      gblibc/src/wait.c
  20. 1 1
      include/asm/boot.h
  21. 2 1
      include/fs/fat.hpp
  22. 1 1
      include/kernel/hw/port.hpp
  23. 1 1
      include/kernel/hw/timer.h
  24. 8 0
      include/kernel/log.hpp
  25. 1 1
      include/kernel/mem.h
  26. 1 1
      include/kernel/process.hpp
  27. 1 1
      include/kernel/tty.hpp
  28. 1 1
      include/kernel/vfs.hpp
  29. 1 1
      include/kernel/vga.hpp
  30. 1 1
      include/types/allocator.hpp
  31. 1 1
      include/types/bitmap.h
  32. 1 1
      include/types/buffer.hpp
  33. 1 1
      include/types/cplusplus.hpp
  34. 3 2
      include/types/elf.hpp
  35. 1 1
      include/types/hash_map.hpp
  36. 1 1
      include/types/lock.hpp
  37. 1 1
      include/types/string.hpp
  38. 2 2
      src/fs/fat.cpp
  39. 2 1
      src/kernel/event/event.cpp
  40. 2 2
      src/kernel/hw/ata.cpp
  41. 1 1
      src/kernel/hw/serial.cpp
  42. 3 2
      src/kernel/interrupt.cpp
  43. 1 1
      src/kernel/mem.cpp
  44. 6 3
      src/kernel/process.cpp
  45. 19 6
      src/kernel/syscall.cpp
  46. 2 2
      src/kernel/tty.cpp
  47. 2 2
      src/kernel/vfs.cpp
  48. 2 2
      src/kernel/vga.cpp
  49. 3 2
      src/kernel_main.cpp
  50. 64 17
      src/types/elf.cpp
  51. 0 4
      user-space-program/.gitignore
  52. 22 0
      user-space-program/CMakeLists.txt
  53. 0 37
      user-space-program/Makefile.src
  54. 7 75
      user-space-program/basic-lib.h
  55. 18 2
      user-space-program/hello-world.s
  56. 30 98
      user-space-program/init.c
  57. 8 8
      user-space-program/interrupt-test.s
  58. 2 0
      user-space-program/script.ld
  59. 106 0
      user-space-program/sh.c
  60. 1 1
      user-space-program/stack-test.s

+ 31 - 54
CMakeLists.txt

@@ -1,37 +1,12 @@
 cmake_minimum_required(VERSION 3.15)
-project(my_os_bootloader ASM)
-
-set(CMAKE_ASM_FLAGS "-m32")
+project(kernel_main C CXX ASM)
 
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 
-include_directories(${PROJECT_SOURCE_DIR}/include)
-
-set(EXTRACT_DIR ${PROJECT_BINARY_DIR}/extract)
-file(MAKE_DIRECTORY ${EXTRACT_DIR})
-
-set(BOOTLOADER_SOURCES src/boot.s
-                       src/asm/a20.s
-                       src/asm/interrupt.s
-                       src/asm/port_io.s
-                       src/asm/sys.s
-                       )
-
-add_library(bootloader STATIC ${BOOTLOADER_SOURCES})
-
-add_custom_command(OUTPUT mbr.bin
-    DEPENDS ${PROJECT_SOURCE_DIR}/src/mbr.S ${PROJECT_SOURCE_DIR}/src/mbr.ld
-    COMMAND ${CMAKE_ASM_COMPILER} -m32 -c ${PROJECT_SOURCE_DIR}/src/mbr.S -o mbr.o
-    COMMAND ${CMAKE_LINKER} -T ${PROJECT_SOURCE_DIR}/src/mbr.ld mbr.o -o mbr.bin
-)
-
-add_custom_command(OUTPUT extracted_bootloader
-    DEPENDS bootloader
-    COMMAND ${CMAKE_AR} xf ${PROJECT_BINARY_DIR}/libbootloader.a --output=${EXTRACT_DIR}
-)
-
-project(kernel_main)
+set(CMAKE_CXX_LINK_EXECUTABLE
+    "<CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
+set(CMAKE_ASM_FLAGS "-m32")
 set(CMAKE_C_FLAGS "-nostdinc -m32 -nostdlib -W -Wall -Wextra -Wno-builtin-declaration-mismatch -Wno-format -Werror=implicit-int -Werror=implicit-function-declaration -Werror=strict-aliasing -fverbose-asm -fno-exceptions -fno-pic -ffreestanding -mstack-protector-guard=global")
 set(CMAKE_CXX_FLAGS "-nostdinc -m32 -nostdlib -W -Wall -Wextra -Wno-builtin-declaration-mismatch -Wno-format -fverbose-asm -fno-use-cxa-atexit -fno-exceptions -fno-pic -ffreestanding -fno-rtti -mstack-protector-guard=global")
 set(CMAKE_CXX_STANDARD 20)
@@ -48,13 +23,22 @@ if (NOT DEFINED FDISK_BIN)
     set(FDISK_BIN fdisk)
 endif()
 
+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/kernel/errno.c
                         src/kernel/interrupt.cpp
                         src/kernel/process.cpp
                         src/kernel/tty.cpp
-                        src/kernel/stdio.cpp
                         src/kernel/syscall.cpp
                         src/kernel/mem.cpp
                         src/kernel/vfs.cpp
@@ -77,7 +61,6 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/kernel/tty.hpp
                         include/kernel/interrupt.h
                         include/kernel/process.hpp
-                        include/kernel/stdio.hpp
                         include/kernel/syscall.hpp
                         include/kernel/mem.h
                         include/kernel/mm.hpp
@@ -100,7 +83,6 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/types.h
                         include/types/size.h
                         include/types/status.h
-                        include/types/stdint.h
                         include/types/allocator.hpp
                         include/types/cplusplus.hpp
                         include/types/list.hpp
@@ -108,30 +90,24 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/string.hpp
                         include/types/vector.hpp
                         include/types/function.hpp
+                        include/kernel/log.hpp
                         include/kernel_main.hpp
                         )
-add_library(kernel_main STATIC ${KERNEL_MAIN_SOURCES})
 
-add_custom_command(OUTPUT extracted_kernel_main
-    DEPENDS kernel_main
-    COMMAND ${CMAKE_AR} xf ${PROJECT_BINARY_DIR}/libkernel_main.a --output=${EXTRACT_DIR}
-)
+add_executable(kernel.out ${KERNEL_MAIN_SOURCES} ${BOOTLOADER_SOURCES})
+target_link_libraries(kernel.out gblibc)
+target_include_directories(kernel.out PRIVATE ${PROJECT_SOURCE_DIR}/include)
+target_link_options(kernel.out PRIVATE
+    -T ${CMAKE_SOURCE_DIR}/src/kernel.ld -melf_i386 -lgblibc -L${CMAKE_BINARY_DIR}/gblibc)
+set_target_properties(kernel.out PROPERTIES LINK_DEPENDS ${CMAKE_SOURCE_DIR}/src/kernel.ld)
 
-add_custom_target(user_space_programs
-    COMMAND cp ${CMAKE_SOURCE_DIR}/user-space-program/Makefile.src ${CMAKE_SOURCE_DIR}/user-space-program/Makefile
-    COMMAND make -C ${CMAKE_SOURCE_DIR}/user-space-program CROSS_COMPILE=${TOOLCHAIN_PATH_AND_PREFIX} all
-)
-
-add_custom_target(kernel.out
-    DEPENDS extracted_bootloader
-    DEPENDS extracted_kernel_main
-    DEPENDS user_space_programs
-    DEPENDS ${CMAKE_SOURCE_DIR}/src/kernel.ld
-    COMMAND ${CMAKE_LINKER} -T ${CMAKE_SOURCE_DIR}/src/kernel.ld ${EXTRACT_DIR}/*.o
-    -melf_i386 -o ${CMAKE_BINARY_DIR}/kernel.out
+add_custom_command(OUTPUT mbr.bin
+    DEPENDS ${PROJECT_SOURCE_DIR}/src/mbr.S ${PROJECT_SOURCE_DIR}/src/mbr.ld
+    COMMAND ${CMAKE_ASM_COMPILER} -m32 -c ${PROJECT_SOURCE_DIR}/src/mbr.S -o mbr.o
+    COMMAND ${CMAKE_LINKER} -T ${PROJECT_SOURCE_DIR}/src/mbr.ld mbr.o -o mbr.bin
 )
 
-add_custom_target(mbr_hole.bin
+add_custom_command(OUTPUT mbr_hole.bin
     DEPENDS kernel.out
     COMMAND ${CMAKE_OBJCOPY} --strip-debug -O binary ${CMAKE_BINARY_DIR}/kernel.out mbr_hole.bin
 )
@@ -145,10 +121,11 @@ 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_SOURCE_DIR}/user-space-program/build/hello-world.out ::hello.out
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/interrupt-test.out ::int.out
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/stack-test.out ::stack.out
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/user-space-program/build/init.out ::init.elf
+    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
 )
 
 add_custom_command(OUTPUT run

+ 20 - 0
gblibc/CMakeLists.txt

@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.15)
+project(gblibc)
+
+add_library(gblibc STATIC
+    src/stdio.c
+    src/arithmetic.c
+    src/string.c
+    src/crt0.s
+    src/fcntl.c
+    src/unistd.c
+    src/wait.c
+)
+
+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")

+ 16 - 0
gblibc/include/fcntl.h

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_FCNTL_H_
+#define __GBLIBC_FCNTL_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int open(const char* filename, int flags, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 11 - 0
gblibc/include/stdarg.h

@@ -0,0 +1,11 @@
+#ifndef __GBLIBC_STDARG_H_
+#define __GBLIBC_STDARG_H_
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_copy(v, l) __builtin_va_copy(v, l)
+
+#endif

+ 7 - 3
include/types/stdint.h → gblibc/include/stdint.h

@@ -1,5 +1,7 @@
-#pragma once
+#ifndef __GBLIBC_STDINT_H_
+#define __GBLIBC_STDINT_H_
 
+#undef NULL
 #ifdef __cplusplus
 #define NULL (nullptr)
 #else
@@ -19,5 +21,7 @@ typedef __UINT64_TYPE__ uint64_t;
 typedef __SIZE_TYPE__ size_t;
 typedef int32_t ssize_t;
 
-typedef uint32_t time_t;
-typedef int32_t time_diff_t;
+typedef size_t time_t;
+typedef ssize_t time_diff_t;
+
+#endif

+ 19 - 0
gblibc/include/stdio.h

@@ -0,0 +1,19 @@
+#ifndef __GBLIBC_STDIO_H_
+#define __GBLIBC_STDIO_H_
+
+#include <stdint.h>
+
+#undef EOF
+#define EOF (-1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int snprintf(char* buf, size_t bufsize, const char* fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 10 - 23
include/kernel/stdio.hpp → gblibc/include/string.h

@@ -1,14 +1,12 @@
-#pragma once
+#ifndef __GBLIBC_STRING_H_
+#define __GBLIBC_STRING_H_
 
-#include <types/stdint.h>
+#include <stdint.h>
 
-#ifndef CR
+#undef CR
+#undef LF
 #define CR ('\r')
-#endif
-
-#ifndef LF
 #define LF ('\n')
-#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -16,25 +14,14 @@ extern "C" {
 
 void* memcpy(void* dst, const void* src, size_t n);
 void* memset(void* dst, int c, size_t n);
-size_t strlen(const char* str);
-char* strncpy(char* dst, const char* src, size_t n);
-int strcmp(const char* s1, const char* s2);
 
-ssize_t
-snprint_decimal(
-    char* buf,
-    size_t buf_size,
-    int32_t num);
-
-ssize_t
-snprintf(
-    char* buf,
-    size_t buf_size,
-    const char* fmt,
-    ...);
+int strcmp(const char* s1, const char* s2);
+size_t strlen(const char* str);
 
-void kmsg(const char* msg);
+char* strncpy(char* dst, const char* src, size_t n);
 
 #ifdef __cplusplus
 }
 #endif
+
+#endif

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

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_SYS_TYPES_H
+#define __GBLIBC_SYS_TYPES_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef ssize_t pid_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

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

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_SYS_WAIT_H
+#define __GBLIBC_SYS_WAIT_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+pid_t wait(int* code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 23 - 0
gblibc/include/unistd.h

@@ -0,0 +1,23 @@
+#ifndef __GBLIBC_UNISTD_H_
+#define __GBLIBC_UNISTD_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ssize_t read(int fd, void* buf, size_t count);
+ssize_t write(int fd, const void* buf, size_t count);
+
+_Noreturn void _exit(int code);
+pid_t fork(void);
+int execve(const char* pathname, char* const argv[], char* const envp[]);
+
+unsigned int sleep(unsigned int seconds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 11 - 0
gblibc/private-include/devutil.h

@@ -0,0 +1,11 @@
+#ifndef __GBLIBC_DEVUTIL_H_
+#define __GBLIBC_DEVUTIL_H_
+
+#ifdef __i386__
+
+#define __GBLIBC__X86_SYSTEM_
+#define __32bit_system
+
+#endif
+
+#endif

+ 76 - 0
gblibc/private-include/syscall.h

@@ -0,0 +1,76 @@
+#ifndef __GBLIBC_SYSCALL_H_
+#define __GBLIBC_SYSCALL_H_
+
+#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)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline uint32_t syscall0(uint32_t no)
+{
+    asm volatile(
+        "movl %1, %%eax\n"
+        "int $0x80\n"
+        "movl %%eax, %0"
+        : "=g"(no)
+        : "g"(no)
+        : "eax");
+    return no;
+}
+static inline uint32_t syscall1(uint32_t no, uint32_t arg)
+{
+    asm volatile(
+        "movl %1, %%edi\n"
+        "movl %2, %%eax\n"
+        "int $0x80\n"
+        "movl %%eax, %0"
+        : "=g"(no)
+        : "g"(arg), "g"(no)
+        : "eax", "edi");
+    return no;
+}
+static inline uint32_t syscall2(uint32_t no, uint32_t arg1, uint32_t arg2)
+{
+    asm volatile(
+        "movl %1, %%edi\n"
+        "movl %2, %%esi\n"
+        "movl %3, %%eax\n"
+        "int $0x80\n"
+        "movl %%eax, %0"
+        : "=g"(no)
+        : "g"(arg1), "g"(arg2), "g"(no)
+        : "eax", "edi", "esi");
+    return no;
+}
+static inline uint32_t syscall3(uint32_t no, uint32_t arg1, uint32_t arg2, uint32_t arg3)
+{
+    asm volatile(
+        "movl %1, %%edi\n"
+        "movl %2, %%esi\n"
+        "movl %3, %%edx\n"
+        "movl %4, %%eax\n"
+        "int $0x80\n"
+        "movl %%eax, %0"
+        : "=g"(no)
+        : "g"(arg1), "g"(arg2), "g"(arg3), "g"(no)
+        : "eax", "edx", "edi", "esi");
+    return no;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 53 - 0
gblibc/src/arithmetic.c

@@ -0,0 +1,53 @@
+#include <devutil.h>
+#include <stdint.h>
+
+static inline uint64_t do_div(uint64_t a, uint64_t b, uint64_t* remainder)
+{
+    uint64_t r = 0, q = 0;
+    for (int32_t i = 0; i < 64; i++) {
+        r = (r << 1) + (a >> 63);
+        a <<= 1;
+        q <<= 1;
+        if (r >= b) {
+            r -= b;
+            q += 1;
+        }
+    }
+    if (remainder)
+        *remainder = r;
+    return q;
+}
+
+static inline int64_t do_div_s(int64_t a, int64_t b, uint64_t* remainder)
+{
+    int32_t qf = 0, rf = 0;
+    if (a < 0) {
+        qf = rf = 1;
+        a = -a;
+    }
+    if (b < 0) {
+        qf ^= 1;
+        b = -b;
+    }
+
+    int64_t quotient = do_div(a, b, (uint64_t*)remainder);
+
+    if (qf)
+        quotient = -quotient;
+    if (remainder && rf)
+        *remainder = -*remainder;
+
+    return quotient;
+}
+
+int64_t __divdi3(int64_t a, int64_t b)
+{
+    return do_div_s(a, b, (uint64_t*)0);
+}
+
+int64_t __moddi3(int64_t a, int64_t b)
+{
+    uint64_t remainder = 0;
+    do_div_s(a, b, &remainder);
+    return remainder;
+}

+ 27 - 0
gblibc/src/crt0.s

@@ -0,0 +1,27 @@
+.code32
+
+.text
+
+# TODO: call .init and .fini, initialize c standard library
+.globl _start
+.type  _start @function
+_start:
+    movl (%esp), %eax   # argc
+    leal 4(%esp), %ecx  # argv
+    movl %esp, %edx
+
+    andl $0xfffffff0, %esp
+
+    pushl %edx
+    pushl $0
+
+    movl %esp, %ebp
+
+    pushl %ecx
+    pushl %eax
+
+    call main
+
+    movl %eax, %edi  # code
+    movl $0x05, %eax # SYS_exit
+    int $0x80        # syscall

+ 7 - 0
gblibc/src/fcntl.c

@@ -0,0 +1,7 @@
+#include <fcntl.h>
+#include <syscall.h>
+
+int open(const char* filename, int flags, ...)
+{
+    return syscall2(SYS_open, (uint32_t)filename, flags);
+}

+ 27 - 165
src/kernel/stdio.cpp → gblibc/src/stdio.c

@@ -1,64 +1,6 @@
-#include <kernel/stdio.hpp>
-#include <kernel/tty.hpp>
-
-#include <types/size.h>
-#include <types/stdint.h>
-
-#define __32bit_system
-
-#ifdef __32bit_system
-uint64_t do_div(uint64_t a, uint64_t b, uint64_t* remainder)
-{
-    uint64_t r = 0, q = 0;
-    int32_t i;
-    for (i = 0; i < 64; i++) {
-        r = (r << 1) + (a >> 63);
-        a <<= 1;
-        q <<= 1;
-        if (r >= b) {
-            r -= b;
-            q += 1;
-        }
-    }
-    if (remainder)
-        *remainder = r;
-    return q;
-}
-
-int64_t do_div_s(int64_t a, int64_t b, uint64_t* remainder)
-{
-    int32_t qf = 0, rf = 0;
-    if (a < 0) {
-        qf = rf = 1;
-        a = -a;
-    }
-    if (b < 0) {
-        qf ^= 1;
-        b = -b;
-    }
-
-    int64_t quotient = do_div(a, b, (uint64_t*)remainder);
-
-    if (qf)
-        quotient = -quotient;
-    if (remainder && rf)
-        *remainder = -*remainder;
-
-    return quotient;
-}
-
-extern "C" int64_t __divdi3(int64_t a, int64_t b)
-{
-    return do_div_s(a, b, (uint64_t*)0);
-}
-
-extern "C" int64_t __moddi3(int64_t a, int64_t b)
-{
-    uint64_t remainder = 0;
-    do_div_s(a, b, &remainder);
-    return remainder;
-}
-#endif
+#include <devutil.h>
+#include <stdint.h>
+#include <stdarg.h>
 
 // where n is in the range of [0, 9]
 static inline char d_to_c(int32_t n)
@@ -105,7 +47,7 @@ static inline char X_to_c(int32_t n)
         --(y);                    \
     }
 
-ssize_t
+static inline ssize_t
 snprint_decimal32(
     char* buf,
     size_t buf_size,
@@ -146,7 +88,7 @@ snprint_decimal32(
     return n_write;
 }
 
-ssize_t
+static inline ssize_t
 snprint_decimal64(
     char* buf,
     size_t buf_size,
@@ -187,7 +129,7 @@ snprint_decimal64(
     return n_write;
 }
 
-ssize_t
+static inline ssize_t
 snprint_hex32(
     char* buf,
     size_t buf_size,
@@ -235,7 +177,7 @@ snprint_hex32(
     return n_write;
 }
 
-ssize_t
+static inline ssize_t
 snprint_hex64(
     char* buf,
     size_t buf_size,
@@ -294,15 +236,12 @@ snprint_char(
     return sizeof(c);
 }
 
-ssize_t
-snprintf(
-    char* buf,
-    size_t buf_size,
-    const char* fmt,
-    ...)
+int snprintf(char* buf, size_t buf_size, const char* fmt, ...)
 {
     ssize_t n_write = 0;
-    uint8_t* arg_ptr = ((uint8_t*)&buf) + sizeof(char*) + sizeof(size_t) + sizeof(const char*);
+
+    va_list arg;
+    va_start(arg, fmt);
 
     for (char c; (c = *fmt) != 0x00; ++fmt) {
         if (c == '%') {
@@ -310,20 +249,17 @@ snprintf(
 
             switch (*(++fmt)) {
 
-            // int32 decimal
+            // int
             case 'd':
-                n_tmp_write = snprint_decimal32(buf, buf_size, *(int32_t*)arg_ptr);
-                arg_ptr += sizeof(int32_t);
+                n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, int));
                 break;
 
             case 'x':
-                n_tmp_write = snprint_hex32(buf, buf_size, *(uint32_t*)arg_ptr, 0);
-                arg_ptr += sizeof(uint32_t);
+                n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 0);
                 break;
 
             case 'X':
-                n_tmp_write = snprint_hex32(buf, buf_size, *(uint32_t*)arg_ptr, 1);
-                arg_ptr += sizeof(uint32_t);
+                n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 1);
                 break;
 
             // long decimal
@@ -333,54 +269,47 @@ snprintf(
                 case 'l':
                     switch (*(++fmt)) {
                     case 'd':
-                        n_tmp_write = snprint_decimal64(buf, buf_size, *(int64_t*)arg_ptr);
+                        n_tmp_write = snprint_decimal64(buf, buf_size, va_arg(arg, long long));
                         break;
                     case 'x':
-                        n_tmp_write = snprint_hex64(buf, buf_size, *(int64_t*)arg_ptr, 0);
+                        n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 0);
                         break;
                     case 'X':
-                        n_tmp_write = snprint_hex64(buf, buf_size, *(int64_t*)arg_ptr, 1);
+                        n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 1);
                         break;
                     }
-                    arg_ptr += sizeof(int64_t);
                     break;
                 // long int aka int32
                 case 'd':
-                    n_tmp_write = snprint_decimal32(buf, buf_size, *(int32_t*)arg_ptr);
-                    arg_ptr += sizeof(int32_t);
+                    n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, long));
                     break;
                 case 'x':
-                    n_tmp_write = snprint_hex32(buf, buf_size, *(uint32_t*)arg_ptr, 0);
-                    arg_ptr += sizeof(uint32_t);
+                    n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 0);
                     break;
 
                 case 'X':
-                    n_tmp_write = snprint_hex32(buf, buf_size, *(uint32_t*)arg_ptr, 1);
-                    arg_ptr += sizeof(uint32_t);
+                    n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 1);
                     break;
                 }
                 break;
 
             // c string
             case 's':
-                n_tmp_write = snprintf(buf, buf_size, *(const char**)arg_ptr);
-                arg_ptr += sizeof(const char*);
+                n_tmp_write = snprintf(buf, buf_size, va_arg(arg, const char*));
                 break;
 
             // int8 char
             case 'c':
-                n_tmp_write = snprint_char(buf, buf_size, *(char*)arg_ptr);
-                arg_ptr += sizeof(char);
+                n_tmp_write = snprint_char(buf, buf_size, va_arg(arg, int));
                 break;
 
             // pointer
             case 'p':
 #ifdef __32bit_system
-                n_tmp_write = snprint_hex32(buf, buf_size, *(ptr_t*)arg_ptr, 0);
+                n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, size_t), 0);
 #else
-                n_tmp_write = snprint_hex64(buf, buf_size, *(ptr_t*)arg_ptr, 0);
+                n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, size_t), 0);
 #endif
-                arg_ptr += sizeof(ptr_t);
                 break;
 
             default:
@@ -410,74 +339,7 @@ snprintf(
     if (buf_size > 0)
         *buf = 0x00;
 
-    return n_write;
-}
-
-#define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
-void* memcpy(void* _dst, const void* _src, size_t n)
-{
-    void* orig_dst = _dst;
-    uint8_t* dst = (uint8_t*)_dst;
-    const uint8_t* src = (const uint8_t*)_src;
-    for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
-        *(uint32_t*)dst = *(uint32_t*)src;
-        dst += BYTES_PER_MAX_COPY_UNIT;
-        src += BYTES_PER_MAX_COPY_UNIT;
-    }
-    for (size_t i = 0; i < (n % BYTES_PER_MAX_COPY_UNIT); ++i) {
-        *((char*)dst++) = *((char*)src++);
-    }
-    return orig_dst;
-}
+    va_end(arg);
 
-void* memset(void* _dst, int c, size_t n)
-{
-    uint8_t* dst = (uint8_t*)_dst;
-    c &= 0xff;
-    int cc = (c + (c << 8) + (c << 16) + (c << 24));
-    for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
-        *(uint32_t*)dst = cc;
-        dst += BYTES_PER_MAX_COPY_UNIT;
-    }
-    for (size_t i = 0; i < (n % BYTES_PER_MAX_COPY_UNIT); ++i) {
-        *((char*)dst++) = c;
-    }
-    return dst;
-}
-
-size_t strlen(const char* str)
-{
-    size_t n = 0;
-    while (*(str++) != '\0')
-        ++n;
-    return n;
-}
-
-char* strncpy(char* dst, const char* src, size_t n)
-{
-    size_t len = strlen(src);
-
-    if (len < n) {
-        memset(dst + len, 0x00, n - len);
-        memcpy(dst, src, len);
-    } else {
-        memcpy(dst, src, n);
-    }
-
-    return dst;
-}
-
-int strcmp(const char* s1, const char* s2)
-{
-    int c;
-    while ((c = *s1 - *s2) == 0 && *s1 != 0) {
-        ++s1;
-        ++s2;
-    }
-    return c;
-}
-
-void kmsg(const char* msg)
-{
-    console->print(msg);
+    return n_write;
 }

+ 66 - 0
gblibc/src/string.c

@@ -0,0 +1,66 @@
+#include <stdint.h>
+
+#define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
+
+void* memcpy(void* _dst, const void* _src, size_t n)
+{
+    void* orig_dst = _dst;
+    uint8_t* dst = (uint8_t*)_dst;
+    const uint8_t* src = (const uint8_t*)_src;
+    for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
+        *(uint32_t*)dst = *(uint32_t*)src;
+        dst += BYTES_PER_MAX_COPY_UNIT;
+        src += BYTES_PER_MAX_COPY_UNIT;
+    }
+    for (size_t i = 0; i < (n % BYTES_PER_MAX_COPY_UNIT); ++i) {
+        *((char*)dst++) = *((char*)src++);
+    }
+    return orig_dst;
+}
+
+void* memset(void* _dst, int c, size_t n)
+{
+    uint8_t* dst = (uint8_t*)_dst;
+    c &= 0xff;
+    int cc = (c + (c << 8) + (c << 16) + (c << 24));
+    for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
+        *(uint32_t*)dst = cc;
+        dst += BYTES_PER_MAX_COPY_UNIT;
+    }
+    for (size_t i = 0; i < (n % BYTES_PER_MAX_COPY_UNIT); ++i) {
+        *((char*)dst++) = c;
+    }
+    return dst;
+}
+
+size_t strlen(const char* str)
+{
+    size_t n = 0;
+    while (*(str++) != '\0')
+        ++n;
+    return n;
+}
+
+char* strncpy(char* dst, const char* src, size_t n)
+{
+    size_t len = strlen(src);
+
+    if (len < n) {
+        memset(dst + len, 0x00, n - len);
+        memcpy(dst, src, len);
+    } else {
+        memcpy(dst, src, n);
+    }
+
+    return dst;
+}
+
+int strcmp(const char* s1, const char* s2)
+{
+    int c;
+    while ((c = *s1 - *s2) == 0 && *s1 != 0) {
+        ++s1;
+        ++s2;
+    }
+    return c;
+}

+ 34 - 0
gblibc/src/unistd.c

@@ -0,0 +1,34 @@
+#include <unistd.h>
+#include <syscall.h>
+
+ssize_t read(int fd, void* buf, size_t count)
+{
+    return syscall3(SYS_read, fd, (uint32_t)buf, count);
+}
+
+ssize_t write(int fd, const void* buf, size_t count)
+{
+    return syscall3(SYS_write, fd, (uint32_t)buf, count);
+}
+
+_Noreturn void _exit(int code)
+{
+    (void)syscall1(SYS_exit, code);
+    // if syscall failed
+    for (;;);
+}
+
+pid_t fork(void)
+{
+    return syscall0(SYS_fork);
+}
+
+int execve(const char* pathname, char* const argv[], char* const envp[])
+{
+    return syscall3(SYS_exec, (uint32_t)pathname, (uint32_t)argv, (uint32_t)envp);
+}
+
+unsigned int sleep(unsigned int seconds)
+{
+    return syscall1(SYS_sleep, seconds);
+}

+ 7 - 0
gblibc/src/wait.c

@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include <syscall.h>
+
+pid_t wait(int* code)
+{
+    return syscall1(SYS_wait, (uint32_t)code);
+}

+ 1 - 1
include/asm/boot.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <types/stdint.h>
+#include <stdint.h>
 
 #define KERNEL_EARLY_STACK_ADDR ((phys_ptr_t)0x01000000)
 #define KERNEL_EARLY_STACK_SIZE ((size_t)0x100000)

+ 2 - 1
include/fs/fat.hpp

@@ -2,8 +2,9 @@
 
 #include <kernel/mem.h>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
+#include <string.h>
 #include <types/size.h>
-#include <types/stdint.h>
 
 namespace fs::fat {
 using cluster_t = uint32_t;

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

@@ -1,7 +1,7 @@
 #pragma once
 
+#include <stdint.h>
 #include <types/cplusplus.hpp>
-#include <types/stdint.h>
 
 namespace hw {
 template <typename port_size_t, bool r = true, bool w = true>

+ 1 - 1
include/kernel/hw/timer.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <types/stdint.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {

+ 8 - 0
include/kernel/log.hpp

@@ -0,0 +1,8 @@
+#pragma once
+
+#include <kernel/tty.hpp>
+
+inline void kmsg(const char* msg)
+{
+    console->print(msg);
+}

+ 1 - 1
include/kernel/mem.h

@@ -1,7 +1,7 @@
 #pragma once
 
+#include <stdint.h>
 #include <types/size.h>
-#include <types/stdint.h>
 
 #define PAGE_SIZE (4096)
 #define KERNEL_IDENTICALLY_MAPPED_AREA_LIMIT ((void*)0x30000000)

+ 1 - 1
include/kernel/process.hpp

@@ -6,6 +6,7 @@
 #include <kernel/mm.hpp>
 #include <kernel/task.h>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
 #include <types/hash_map.hpp>
@@ -13,7 +14,6 @@
 #include <types/map.hpp>
 #include <types/pair.hpp>
 #include <types/status.h>
-#include <types/stdint.h>
 #include <types/types.h>
 
 typedef size_t pid_t;

+ 1 - 1
include/kernel/tty.hpp

@@ -1,9 +1,9 @@
 #pragma once
 #include <kernel/event/evtqueue.hpp>
+#include <stdint.h>
 #include <types/allocator.hpp>
 #include <types/buffer.hpp>
 #include <types/cplusplus.hpp>
-#include <types/stdint.h>
 
 class tty : public types::non_copyable {
 public:

+ 1 - 1
include/kernel/vfs.hpp

@@ -1,11 +1,11 @@
 #pragma once
 
+#include <stdint.h>
 #include <types/allocator.hpp>
 #include <types/function.hpp>
 #include <types/hash_map.hpp>
 #include <types/list.hpp>
 #include <types/map.hpp>
-#include <types/stdint.h>
 #include <types/types.h>
 #include <types/vector.hpp>
 

+ 1 - 1
include/kernel/vga.hpp

@@ -2,7 +2,7 @@
 #ifndef _KERNEL_VGA_H_
 #define _KERNEL_VGA_H_
 
-#include <types/stdint.h>
+#include <stdint.h>
 
 #define VGA_CHAR_COLOR_WHITE (0x0fU)
 

+ 1 - 1
include/types/allocator.hpp

@@ -1,7 +1,7 @@
 #pragma once
 #include <kernel/mem.h>
+#include <stdint.h>
 #include <types/cplusplus.hpp>
-#include <types/stdint.h>
 #include <types/types.h>
 
 constexpr void* operator new(size_t, void* ptr)

+ 1 - 1
include/types/bitmap.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <types/stdint.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {

+ 1 - 1
include/types/buffer.hpp

@@ -1,7 +1,7 @@
 #pragma once
 
+#include <stdint.h>
 #include <types/allocator.hpp>
-#include <types/stdint.h>
 
 namespace types {
 

+ 1 - 1
include/types/cplusplus.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <types/stdint.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 

+ 3 - 2
include/types/elf.hpp

@@ -3,9 +3,9 @@
 #include <kernel/interrupt.h>
 #include <kernel/process.hpp>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
 #include <types/size.h>
 #include <types/status.h>
-#include <types/stdint.h>
 
 namespace types::elf {
 using elf32_addr_t = uint32_t;
@@ -111,7 +111,8 @@ struct PACKED elf32_program_header_entry {
 
 struct elf32_load_data {
     const char* exec;
-    const char** argv;
+    const char* const* argv;
+    const char* const* envp;
     int errcode;
     void* eip;
     uint32_t* sp;

+ 1 - 1
include/types/hash_map.hpp

@@ -1,10 +1,10 @@
 #pragma once
 
+#include <stdint.h>
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
 #include <types/list.hpp>
 #include <types/pair.hpp>
-#include <types/stdint.h>
 #include <types/string.hpp>
 #include <types/types.h>
 #include <types/vector.hpp>

+ 1 - 1
include/types/lock.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <types/stdint.h>
+#include <stdint.h>
 
 inline void spin_lock(uint32_t volatile* lock_addr)
 {

+ 1 - 1
include/types/string.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <kernel/stdio.hpp>
+#include <string.h>
 #include <types/allocator.hpp>
 #include <types/types.h>
 #include <types/vector.hpp>

+ 2 - 2
src/fs/fat.cpp

@@ -1,13 +1,13 @@
 #include <fs/fat.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
-#include <kernel/stdio.hpp>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/hash_map.hpp>
 #include <types/status.h>
-#include <types/stdint.h>
 
 namespace fs::fat {
 // buf MUST be larger than 512 bytes

+ 2 - 1
src/kernel/event/event.cpp

@@ -2,8 +2,9 @@
 #include <kernel/event/event.h>
 #include <kernel/event/evtqueue.hpp>
 #include <kernel/input/input_event.h>
+#include <kernel/log.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.hpp>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/cplusplus.hpp>

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

@@ -1,13 +1,13 @@
 #include <asm/port_io.h>
 #include <fs/fat.hpp>
 #include <kernel/hw/ata.hpp>
-#include <kernel/stdio.hpp>
 #include <kernel/syscall.hpp>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/status.h>
-#include <types/stdint.h>
 
 hw::ata::ata(port_id_t p)
     : data(p)

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

@@ -1,7 +1,7 @@
 #include <asm/port_io.h>
 #include <kernel/hw/serial.h>
-#include <kernel/stdio.hpp>
 #include <kernel/tty.hpp>
+#include <stdio.h>
 #include <types/status.h>
 
 int32_t init_serial_port(port_id_t port)

+ 3 - 2
src/kernel/interrupt.cpp

@@ -5,17 +5,18 @@
 #include <kernel/hw/serial.h>
 #include <kernel/hw/timer.h>
 #include <kernel/interrupt.h>
+#include <kernel/log.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.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/assert.h>
 #include <types/size.h>
-#include <types/stdint.h>
 #include <types/types.h>
 
 static struct IDT_entry IDT[256];

+ 1 - 1
src/kernel/mem.cpp

@@ -5,10 +5,10 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.hpp>
 #include <kernel/task.h>
 #include <kernel/vga.hpp>
 #include <kernel_main.hpp>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/bitmap.h>

+ 6 - 3
src/kernel/process.cpp

@@ -3,12 +3,14 @@
 #include <fs/fat.hpp>
 #include <kernel/hw/ata.hpp>
 #include <kernel/interrupt.h>
+#include <kernel/log.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.hpp>
 #include <kernel/vfs.hpp>
 #include <kernel_main.hpp>
+#include <stdint.h>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/cplusplus.hpp>
@@ -18,7 +20,6 @@
 #include <types/lock.hpp>
 #include <types/size.h>
 #include <types/status.h>
-#include <types/stdint.h>
 #include <types/types.h>
 
 static void (*volatile kthreadd_new_thd_func)(void*);
@@ -165,11 +166,13 @@ void NORETURN _kernel_init(void)
     current_process->attr.system = 0;
     current_thread->attr.system = 0;
 
-    const char* argv[] = { "/mnt/INIT.ELF", nullptr };
+    const char* argv[] = { "/mnt/INIT.ELF", "/mnt/SH.ELF", nullptr };
+    const char* envp[] = { nullptr };
 
     types::elf::elf32_load_data d;
     d.exec = "/mnt/INIT.ELF";
     d.argv = argv;
+    d.envp = envp;
     d.system = false;
 
     assert(types::elf::elf32_load(&d) == GB_OK);

+ 19 - 6
src/kernel/syscall.cpp

@@ -2,18 +2,20 @@
 #include <asm/sys.h>
 #include <kernel/errno.h>
 #include <kernel/interrupt.h>
+#include <kernel/log.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.hpp>
 #include <kernel/syscall.hpp>
+#include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
 #include <kernel_main.hpp>
+#include <stdint.h>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/elf.hpp>
 #include <types/status.h>
-#include <types/stdint.h>
 
 #define SYSCALL_SET_RETURN_VAL_EAX(_eax) \
     data->s_regs.eax = ((decltype(data->s_regs.eax))(_eax))
@@ -130,19 +132,24 @@ void _syscall_crash(interrupt_stack*)
 // 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)
 {
     const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
-    const char** argv = reinterpret_cast<const char**>(data->s_regs.esi);
-
-    current_process->mms.clear_user();
+    char* const* argv = reinterpret_cast<char* const*>(data->s_regs.esi);
+    char* const* envp = reinterpret_cast<char* const*>(data->s_regs.edx);
 
     types::elf::elf32_load_data d;
     d.argv = argv;
+    d.envp = envp;
     d.exec = exec;
     d.system = false;
 
-    assert(types::elf::elf32_load(&d) == GB_OK);
+    int ret = types::elf::elf32_load(&d);
+    if (ret != GB_OK) {
+        data->s_regs.eax = d.errcode;
+        return;
+    }
 
     data->v_eip = d.eip;
     data->esp = (uint32_t)d.sp;
@@ -173,6 +180,12 @@ void _syscall_exit(interrupt_stack* data)
     // unmap all user memory areas
     current_process->mms.clear_user();
 
+    // init should never exit
+    if (current_process->ppid == 0) {
+        console->print("kernel panic: init exited!\n");
+        crash();
+    }
+
     // make child processes orphans (children of init)
     procs->make_children_orphans(pid);
 

+ 2 - 2
src/kernel/tty.cpp

@@ -1,9 +1,9 @@
 #include <kernel/hw/serial.h>
 #include <kernel/process.hpp>
-#include <kernel/stdio.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vga.hpp>
-#include <types/stdint.h>
+#include <stdint.h>
+#include <stdio.h>
 
 tty::tty()
     : buf(BUFFER_SIZE)

+ 2 - 2
src/kernel/vfs.cpp

@@ -1,15 +1,15 @@
 #include <kernel/errno.h>
 #include <kernel/mem.h>
-#include <kernel/stdio.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
+#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/list.hpp>
 #include <types/map.hpp>
 #include <types/pair.hpp>
 #include <types/status.h>
-#include <types/stdint.h>
 #include <types/string.hpp>
 #include <types/vector.hpp>
 

+ 2 - 2
src/kernel/vga.cpp

@@ -1,8 +1,8 @@
 #define _KERNEL_VGA_C_
-#include <types/stdint.h>
 
-#include <kernel/stdio.hpp>
 #include <kernel/vga.hpp>
+#include <stdint.h>
+#include <string.h>
 
 static struct vga_char* p_vga_head = VGA_MEM;
 

+ 3 - 2
src/kernel_main.cpp

@@ -8,16 +8,17 @@
 #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/stdio.hpp>
 #include <kernel/task.h>
 #include <kernel/tty.hpp>
 #include <kernel/vga.hpp>
+#include <stdint.h>
+#include <stdio.h>
 #include <types/assert.h>
 #include <types/bitmap.h>
 #include <types/status.h>
-#include <types/stdint.h>
 #include <types/types.h>
 
 #define KERNEL_MAIN_BUF_SIZE (128)

+ 64 - 17
src/types/elf.cpp

@@ -1,15 +1,29 @@
 #include <kernel/errno.h>
-#include <kernel/stdio.hpp>
+#include <kernel/mem.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
 #include <types/assert.h>
 #include <types/elf.hpp>
-#include <types/stdint.h>
+#include <types/string.hpp>
+#include <types/vector.hpp>
+
+#define align16_down(sp) (sp = ((char*)((uint32_t)(sp)&0xfffffff0)))
 
 template <typename T>
-constexpr void _user_push(uint32_t** sp, T d)
+inline void _user_push(char** sp, T d)
 {
     *sp -= sizeof(T);
     *(T*)*sp = d;
 }
+template <>
+inline void _user_push(char** sp, const char* str)
+{
+    size_t len = strlen(str);
+    *sp -= (len + 1);
+    align16_down(*sp);
+    memcpy(*sp, str, len + 1);
+}
 
 int types::elf::elf32_load(types::elf::elf32_load_data* d)
 {
@@ -42,16 +56,34 @@ 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);
+
         d->errcode = EINVAL;
         return GB_FAILED;
     }
 
+    // copy argv and envp
+    vector<string<>> argv, envp;
+    for (const char* const* p = d->argv; *p; ++p)
+        argv.emplace_back(*p);
+    for (const char* const* p = d->envp; *p; ++p)
+        envp.emplace_back(*p);
+
+    // from now on, caller process is recycled.
+    // so we can't just simply return to it on error.
+    current_process->mms.clear_user();
+
     for (int i = 0; i < hdr.phnum; ++i) {
         if (phents->type != types::elf::elf32_program_header_entry::PT_LOAD)
             continue;
 
         auto ret = mmap((void*)phents->vaddr, phents->memsz, ent_exec->ind, phents->offset, 1, d->system);
         if (ret != GB_OK) {
+            k_free(phents);
+
+            // TODO: kill process
+            assert(false);
+
             d->errcode = ret;
             return GB_FAILED;
         }
@@ -60,31 +92,46 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     }
 
     // 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,
+        fs::vfs_open("/dev/null")->ind, 0, 1, 0);
     assert_likely(ret == GB_OK);
 
     d->eip = (void*)hdr.entry;
     d->sp = reinterpret_cast<uint32_t*>(types::elf::ELF_STACK_BOTTOM);
 
-    auto* sp = &d->sp;
+    auto* sp = (char**)&d->sp;
 
-    types::vector<const char*> arr;
-    for (const char** ptr = d->argv; *ptr != nullptr; ++ptr) {
-        auto len = strlen(*ptr);
-        *sp -= (len + 1);
-        *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
-        memcpy((char*)*sp, *ptr, len + 1);
-        arr.push_back((const char*)*sp);
+    // fill information block area
+    vector<char*> args, envs;
+    for (const auto& env : envp) {
+        _user_push(sp, env.c_str());
+        envs.push_back(*sp);
+    }
+    for (const auto& arg : argv) {
+        _user_push(sp, arg.c_str());
+        args.push_back(*sp);
     }
 
-    *sp -= sizeof(const char*) * arr.size();
-    *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
-    memcpy((char*)*sp, arr.data(), sizeof(const char*) * arr.size());
+    // push null auxiliary vector entry
+    _user_push(sp, 0);
+    _user_push(sp, 0);
 
+    // push 0 for envp
     _user_push(sp, 0);
+
+    // push envp
+    *sp -= sizeof(void*) * envs.size();
+    memcpy(*sp, envs.data(), sizeof(void*) * envs.size());
+
+    // push 0 for argv
     _user_push(sp, 0);
-    _user_push(sp, *sp + 8);
-    _user_push(sp, arr.size());
+
+    // push argv
+    *sp -= sizeof(void*) * args.size();
+    memcpy(*sp, args.data(), sizeof(void*) * args.size());
+
+    // push argc
+    _user_push(sp, args.size());
 
     return GB_OK;
 }

+ 0 - 4
user-space-program/.gitignore

@@ -1,4 +0,0 @@
-*.o
-*.bin
-*.res
-user.sym

+ 22 - 0
user-space-program/CMakeLists.txt

@@ -0,0 +1,22 @@
+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")
+
+link_libraries(gblibc)
+add_link_options(-nostdlib -Ttext 0x40000000 -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 "")
+
+add_executable(hello-world.out hello-world.s)
+add_executable(interrupt-test.out interrupt-test.s)
+add_executable(stack-test.out stack-test.s)
+add_executable(init.out init.c)
+add_executable(sh.out sh.c)
+
+add_custom_target(user_space_programs
+    DEPENDS hello-world.out interrupt-test.out stack-test.out init.out sh.out
+)

+ 0 - 37
user-space-program/Makefile.src

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

+ 7 - 75
user-space-program/basic-lib.h

@@ -1,10 +1,7 @@
-typedef __UINT32_TYPE__ uint32_t;
-typedef __UINT16_TYPE__ uint16_t;
-typedef __UINT8_TYPE__ uint8_t;
+#include <stdint.h>
+#include <sys/types.h>
 
-typedef uint32_t pid_t;
-typedef uint32_t size_t;
-typedef size_t ino_t;
+typedef uint32_t ino_t;
 
 #define GNU_ATTRIBUTE(attr) __attribute__((attr))
 #define NORETURN GNU_ATTRIBUTE(noreturn)
@@ -25,66 +22,6 @@ typedef size_t ino_t;
 
 #define DT_MAX (S_DT_MASK + 1) /* 16 */
 
-static inline uint32_t syscall(uint32_t num, uint32_t arg1, uint32_t arg2, uint32_t arg3)
-{
-    asm volatile(
-        "movl %1, %%edi\n"
-        "movl %2, %%esi\n"
-        "movl %3, %%edx\n"
-        "movl %4, %%eax\n"
-        "int $0x80\n"
-        "movl %%eax, %0"
-        : "=g"(num)
-        : "g"(arg1), "g"(arg2), "g"(arg3), "g"(num)
-        : "eax", "edx", "edi", "esi");
-    return num;
-}
-
-static inline void NORETURN syscall_noreturn(uint32_t num, uint32_t arg1, uint32_t arg2, uint32_t arg3)
-{
-    asm volatile(
-        "movl %1, %%edi\n"
-        "movl %2, %%esi\n"
-        "movl %3, %%edx\n"
-        "movl %4, %%eax\n"
-        "int $0x80\n"
-        "movl %%eax, %0"
-        : "=g"(num)
-        : "g"(arg1), "g"(arg2), "g"(arg3), "g"(num)
-        : "eax", "edx", "edi", "esi");
-    // crash
-    syscall_noreturn(0x05, 0, 0, 0);
-}
-
-static inline int fork(void)
-{
-    return syscall(0x00, 0, 0, 0);
-}
-static inline uint32_t write(int fd, const char* buf, size_t count)
-{
-    return syscall(0x01, fd, (uint32_t)buf, count);
-}
-static inline uint32_t read(int fd, char* buf, size_t count)
-{
-    return syscall(0x07, fd, (uint32_t)buf, count);
-}
-static inline void sleep(void)
-{
-    syscall(0x02, 0, 0, 0);
-}
-static inline void NORETURN exec(const char* bin, const char** argv)
-{
-    syscall_noreturn(0x04, (uint32_t)bin, (uint32_t)argv, 0);
-}
-static inline void NORETURN exit(int exit_code)
-{
-    syscall_noreturn(0x05, exit_code, 0, 0);
-}
-static inline uint32_t wait(int* return_value)
-{
-    return syscall(0x06, (uint32_t)return_value, 0, 0);
-}
-
 struct __attribute__((__packed__)) user_dirent {
     ino_t d_ino; // inode number
     uint32_t d_off; // ignored
@@ -93,12 +30,7 @@ struct __attribute__((__packed__)) user_dirent {
     // uint8_t d_type; // file type, with offset of (d_reclen - 1)
 };
 
-static inline size_t getdents(int fd, struct user_dirent* buf, size_t cnt)
-{
-    return syscall(0x08, fd, (uint32_t)buf, cnt);
-}
-
-static inline int open(const char* path, uint32_t flags)
-{
-    return syscall(0x09, (uint32_t)path, flags, 0);
-}
+// static inline size_t getdents(int fd, struct user_dirent* buf, size_t cnt)
+// {
+//     return syscall(0x08, fd, (uint32_t)buf, cnt);
+// }

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

@@ -5,5 +5,21 @@
 .globl main
 main:
 	movl $0xcbcbcbcb, %eax
-	movl $0xacacacac, %ebx
-	jmp .
+	movl $0xacacacac, %edx
+
+	movl $0x01, %eax
+	movl $0, %edi
+	movl $_str, %esi
+	movl $_str_size, %ecx
+	movl (%ecx), %edx
+	int $0x80
+
+	xorl %eax, %eax
+	ret
+
+.data
+_str:
+	.ascii "Hello, World!\n"
+
+_str_size:
+	.long (_str_size - _str)

+ 30 - 98
user-space-program/init.c

@@ -1,114 +1,46 @@
-#include "basic-lib.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
 
-static inline char tc(int n) {
-    return '0' + n;
-}
-
-void print_int(int n) {
-    char buf[12];
-    int len = 0;
-
-    while (n) {
-        int dig = n % 10;
-        buf[len++] = tc(dig);
-        n /= 10;
-    }
-
-    write(0, buf, len);
-}
-
-size_t strlen(const char* str)
-{
-    const char* p = str;
-    while (*p)
-        ++p;
-    return p - str;
-}
-
-static inline void print(const char* str)
-{
-    write(0, str, strlen(str));
-}
+#define print(str) write(0, str, strlen(str))
 
 int main(int argc, char** argv)
 {
-    for (int i = 0; i < argc; ++i)
-        write(0, argv[i], 0);
+    print("***** GBOS INIT SYSTEM *****\n");
 
-    print("Hello World from user space init\n");
-    int ret = fork();
-    if (ret == 0) {
-        print("child\n");
-        exit(255);
-    } else {
-        print("parent\n");
+    pid_t sh_pid = fork();
+    if (sh_pid < 0) {
+        print("[init] unable to fork(), exiting...\n");
+        return -1;
     }
 
-    char buf[128] = {};
-
-    const char* path = "/dev";
-    print("content in ");
-    print(path);
-    print(":\n");
-
-    int dir = open(path, O_RDONLY | O_DIRECTORY);
-    if (dir >= 0) {
-        for (;;) {
-            int n = getdents(dir, (struct user_dirent*)buf, 128);
-            if (n < 0)
-                print("error\n");
-            if (n <= 0)
-                break;
-
-            int bpos = 0;
-            for (; bpos < n;) {
-                struct user_dirent* dirp = (struct user_dirent*)(buf + bpos);
-                print("ino: ");
-                print_int(dirp->d_ino);
-                print(", filename: \"");
-                print(dirp->d_name);
-                print("\", filetype: ");
-                switch (buf[bpos + dirp->d_reclen - 1]) {
-                    case DT_REG:
-                        print("regular file");
-                        break;
-                    case DT_DIR:
-                        print("directory");
-                        break;
-                    case DT_BLK:
-                        print("block device");
-                        break;
-                    default:
-                        print("unknown");
-                        break;
-                }
-                print("\n");
-                bpos += dirp->d_reclen;
-            }
-        }
-    }
+    // child
+    if (sh_pid == 0) {
+        char* shell_argv[128] = {};
+        char* envp[1] = { NULL };
 
-    for (;;) {
-        int n = read(0, buf, 128);
-        if (n)
-            write(0, buf, n);
+        if (argc < 2)
+            shell_argv[0] = "/bin/sh";
         else
-            print("fuck!\n");
+            shell_argv[0] = argv[1];
+        
+        for (int i = 2; i < argc; ++i)
+            shell_argv[i - 1] = argv[i];
         
-        if (buf[0] == 'e' && buf[1] == 'x' && buf[2] == 'i' && buf[3] == 't') {
-            print("\nexited echo mode!\n");
-            break;
-        }
+        execve(shell_argv[0], shell_argv, envp);
+
+        print("[init] unable to run sh, exiting...\n");
+        return -1;
     }
 
+    int ret, pid;
+    char buf[512] = {};
     for (;;) {
-        int ret;
-        pid_t pid = wait(&ret);
-        print("ret: ");
-        print_int(ret);
-        print(", pid: ");
-        print_int(pid);
-        print("\n");
+        pid = wait(&ret);
+        snprintf(buf, sizeof(buf), "[init] pid%d has exited with code %d\n", pid, ret);
+        print(buf);
     }
+
     return 0;
 }

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

@@ -14,16 +14,16 @@ main:
 	movl %eax, %ecx
 # write
 	movl $1, %eax
-	movl $__user_interrupt_test_string, %edi
+	movl $0, %edi
+	movl $__user_interrupt_test_string, %esi
+	movl $(__user_interrupt_test_string_end - __user_interrupt_test_string), %edx
 	int $0x80
-# sleep
-	movl $2, %eax
-	movl $0xffffffff, %edi
-	int $0x80
-# noreturn
-	jmp .
+
+	xorl %eax, %eax
+	ret
 
 .data
 
 __user_interrupt_test_string:
-	.asciz "syscall 0x01 write: hello from user space\n"
+	.ascii "syscall 0x01 write: hello from user space\n"
+__user_interrupt_test_string_end:

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

@@ -1,6 +1,8 @@
 OUTPUT_FORMAT(elf32-i386)
 OUTPUT_ARCH(i386:i386)
 
+ENTRY(_start)
+
 MEMORY
 {
     MEM : org = 0x40000000, l = 3072M

+ 106 - 0
user-space-program/sh.c

@@ -0,0 +1,106 @@
+#include <sys/wait.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define print(str) write(0, str, strlen(str))
+
+// struct cmd {
+//     enum {
+//         pipe,
+//         list,
+//     } op;
+//     struct cmd* left;
+//     struct cmd* right;
+//     struct token* tk;
+// };
+
+// struct token {
+//     char* start;
+//     size_t len;
+
+//     struct token* next;
+// };
+
+// static inline int betwn(char c, char s, char e)
+// {
+//     return c >= s && c <= e;
+// }
+// static inline int is_num(char c)
+// {
+//     return betwn(c, '0', '9');
+// }
+// static inline int check_token(char c)
+// {
+//     return betwn(c, 'a', 'z') || betwn(c, 'A', 'Z') || (c == '_');
+// }
+// static inline int read_token(char* buf, struct token** cur)
+// {
+//     char* p = buf;
+//     for (; *p && (check_token(*p) || (p != buf && is_num(*p))); ++p) {
+//         (*cur)->start = buf;
+//         ++(*cur)->len;
+//     }
+//     if ((*cur)->start) {
+//         (*cur)->next = *cur + 1;
+//         *cur = (*cur)->next;
+//     }
+//     return p - buf;
+// }
+
+int main(int argc, const char** argv)
+{
+    (void)argc, (void)argv;
+    char buf[512] = {};
+
+    print("sh # ");
+
+    for (;;) {
+        int n = read(0, buf, sizeof(buf));
+
+        char token[1024] = {};
+        char* args[128] = { token, 0 };
+        int j = 0;
+        int k = 1;
+
+        for (int i = 0; i < n; ++i) {
+            if (buf[i] == ' ') {
+                token[j++] = 0;
+                args[k++] = token + j;
+                continue;
+            }
+            if (buf[i] == '\n') {
+                token[j++] = 0;
+
+                if (strcmp(args[0], "exit") == 0)
+                    return 0;
+
+                pid_t pid = fork();
+                if (pid == 0) {
+                    char* envp[] = { NULL };
+                    int ret = execve(args[0], args, envp);
+                    char _b[128];
+                    snprintf(_b, sizeof(_b), "sh: execve() failed with code %d\n", ret);
+                    print(_b);
+                    return -1;
+                }
+
+                int code;
+                wait(&code);
+
+                char _b[128];
+                snprintf(_b, sizeof(_b), "sh (%d) # ", code);
+                print(_b);
+
+                j = 0;
+                k = 1;
+                memset(args, 0x00, sizeof(args));
+                args[0] = token;
+                continue;
+            }
+            token[j++] = buf[i];
+        }
+    }
+
+    return 0;
+}

+ 1 - 1
user-space-program/stack-test.s

@@ -13,4 +13,4 @@ main:
 	movl %ebp, %esp
 	popl %ebp
 
-	jmp .
+	ret