Browse Source

Merge branch 'exec'

greatbridf 2 năm trước cách đây
mục cha
commit
e73c206e52
56 tập tin đã thay đổi với 2105 bổ sung1053 xóa
  1. 20 13
      CMakeLists.txt
  2. 1 1
      Makefile.src
  3. 19 1
      configure
  4. 1 0
      cross-compile.cmake
  5. 4 4
      include/asm/sys.h
  6. 1 0
      include/kernel/errno.h
  7. 45 0
      include/kernel/event/evtqueue.hpp
  8. 1 1
      include/kernel/hw/ata.hpp
  9. 8 4
      include/kernel/hw/port.hpp
  10. 9 9
      include/kernel/interrupt.h
  11. 32 34
      include/kernel/mem.h
  12. 280 80
      include/kernel/mm.hpp
  13. 96 25
      include/kernel/process.hpp
  14. 1 3
      include/kernel/syscall.hpp
  15. 0 7
      include/kernel_main.h
  16. 48 7
      include/types/allocator.hpp
  17. 40 0
      include/types/assert.h
  18. 46 9
      include/types/cplusplus.hpp
  19. 124 0
      include/types/elf.hpp
  20. 60 48
      include/types/hash_map.hpp
  21. 46 45
      include/types/list.hpp
  22. 0 35
      include/types/lock.h
  23. 67 0
      include/types/lock.hpp
  24. 1 4
      include/types/size.h
  25. 17 17
      include/types/string.hpp
  26. 8 0
      include/types/types.h
  27. 46 46
      include/types/vector.hpp
  28. 73 0
      pretty-print.py
  29. 12 1
      src/asm/a20.s
  30. 68 45
      src/asm/interrupt.s
  31. 3 1
      src/asm/port_io.s
  32. 0 22
      src/asm/sys.s
  33. 10 10
      src/boot.s
  34. 8 10
      src/fs/fat.cpp
  35. 3 0
      src/kernel.ld
  36. 58 0
      src/kernel/event/event.cpp
  37. 3 5
      src/kernel/hw/ata.cpp
  38. 3 2
      src/kernel/hw/serial.c
  39. 22 24
      src/kernel/interrupt.cpp
  40. 126 204
      src/kernel/mem.cpp
  41. 210 186
      src/kernel/process.cpp
  42. 177 22
      src/kernel/syscall.cpp
  43. 14 9
      src/kernel/vfs.cpp
  44. 31 31
      src/kernel_main.c
  45. 5 1
      src/mbr.S
  46. 90 0
      src/types/elf.cpp
  47. 20 13
      user-space-program/Makefile.src
  48. 62 0
      user-space-program/basic-lib.h
  49. 9 0
      user-space-program/configure
  50. 4 3
      user-space-program/hello-world.s
  51. 25 0
      user-space-program/init.c
  52. 7 4
      user-space-program/interrupt-test.s
  53. 0 20
      user-space-program/output_code.ld
  54. 0 47
      user-space-program/output_symbols.ld
  55. 25 0
      user-space-program/script.ld
  56. 16 0
      user-space-program/stack-test.s

+ 20 - 13
CMakeLists.txt

@@ -32,19 +32,21 @@ add_custom_command(OUTPUT extracted_bootloader
 
 project(kernel_main)
 
-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 -fno-stack-protector")
-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 -fno-stack-protector -fno-rtti")
-set(CMAKE_CXX_STANDARD 17)
+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)
 
 if (CMAKE_BUILD_TYPE STREQUAL "Debug")
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
 elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
 endif()
 
-include_directories(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/user-space-program/build)
+if (NOT DEFINED FDISK_BIN)
+    set(FDISK_BIN fdisk)
+endif()
 
 set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/kernel_main.c
@@ -64,11 +66,13 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/kernel/event/event.cpp
                         src/types/bitmap.c
                         src/types/buffer.c
+                        src/types/elf.cpp
                         include/asm/boot.h
                         include/asm/port_io.h
                         include/asm/sys.h
                         include/fs/fat.hpp
                         include/kernel/event/event.h
+                        include/kernel/event/evtqueue.hpp
                         include/kernel/errno.h
                         include/kernel/tty.h
                         include/kernel/interrupt.h
@@ -86,8 +90,10 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/kernel/hw/timer.h
                         include/kernel/input/keycodes.h
                         include/kernel/input/input_event.h
+                        include/types/assert.h
                         include/types/bitmap.h
                         include/types/buffer.h
+                        include/types/elf.hpp
                         include/types/hash_map.hpp
                         include/types/types.h
                         include/types/size.h
@@ -96,7 +102,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/allocator.hpp
                         include/types/cplusplus.hpp
                         include/types/list.hpp
-                        include/types/lock.h
+                        include/types/lock.hpp
                         include/types/string.hpp
                         include/types/vector.hpp
                         include/kernel_main.h
@@ -111,9 +117,6 @@ add_custom_command(OUTPUT extracted_kernel_main
 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
-    COMMAND mkdir -p ${CMAKE_SOURCE_DIR}/user-space-program/build
-    COMMAND rm -f ${CMAKE_SOURCE_DIR}/user-space-program/build/*
-    COMMAND cp ${CMAKE_SOURCE_DIR}/user-space-program/*.res ${CMAKE_SOURCE_DIR}/user-space-program/build
 )
 
 add_custom_target(kernel.out
@@ -121,7 +124,7 @@ add_custom_target(kernel.out
     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 ${CMAKE_SOURCE_DIR}/user-space-program/user.sym
+    COMMAND ${CMAKE_LINKER} -T ${CMAKE_SOURCE_DIR}/src/kernel.ld ${EXTRACT_DIR}/*.o
     -melf_i386 -o ${CMAKE_BINARY_DIR}/kernel.out
 )
 
@@ -133,12 +136,16 @@ add_custom_target(mbr_hole.bin
 add_custom_target(boot.img
     DEPENDS mbr.bin
     DEPENDS mbr_hole.bin
+    DEPENDS user_space_programs
     COMMAND dd if=mbr.bin of=boot.img
     COMMAND cat mbr_hole.bin >> 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 boot.img
+    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/user.sym ::user.sym
+    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
 )
 
 add_custom_command(OUTPUT run

+ 1 - 1
Makefile.src

@@ -3,7 +3,7 @@ QEMU_BIN=##PLACEHOLDER_1##
 GDB_BIN=##PLACEHOLDER_2##
 QEMU_ACCELERATION_FLAG=##PLACEHOLDER_3##
 QEMU_DEBUG_FLAG=#-d cpu_reset,int
-QEMU_ARGS=-drive file=build/boot.img,format=raw -no-reboot -no-shutdown $(QEMU_ACCELERATION_FLAG) $(QEMU_DEBUG_FLAG)
+QEMU_ARGS=-cpu SandyBridge,check -drive file=build/boot.img,format=raw -no-reboot -no-shutdown $(QEMU_ACCELERATION_FLAG) $(QEMU_DEBUG_FLAG)
 CROSS_COMPILE=##PLACEHOLDER_4##
 .PHONY: run
 run: build

+ 19 - 1
configure

@@ -8,6 +8,7 @@ event() {
 
 # $1: OS NAME
 # $2: CROSS COMPILE FLAG
+# $3: FDISK_BIN
 generate_cross_compile_script() {
 cat > cross-compile.cmake <<EOF
 set(CMAKE_SYSTEM_NAME $1)
@@ -24,6 +25,7 @@ SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 # for libraries and headers in the target directories
 SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+SET(FDISK_BIN $3)
 EOF
 }
 
@@ -85,11 +87,27 @@ case "$OS" in
         ;;
 esac
 
+event "checking util-linux fdisk"
+if [ "$CROSS_COMPILE" = "" -o "$FDISK_BIN" = "" ]; then
+    if ! which fdisk > /dev/null 2>&1; then
+        echo "no"
+        exit 1
+    fi
+    FDISK_BIN=`which fdisk`
+fi
+
+if ! $FDISK_BIN -v 2>&1 | grep util-linux > /dev/null 2>&1 ; then
+    echo "no"
+    exit 1
+else
+    echo "$FDISK_BIN"
+fi
+
 event "checking cross compiling"
 if [ "$CROSS_COMPILE" != "" ]; then
     echo "yes"
     CROSS_COMPILE_FLAG='--toolchain cross-compile.cmake'
-    generate_cross_compile_script "$OS" "$CROSS_COMPILE"
+    generate_cross_compile_script "$OS" "$CROSS_COMPILE" "$FDISK_BIN"
 else
     echo "no"
     CROSS_COMPILE_FLAG=

+ 1 - 0
cross-compile.cmake

@@ -12,3 +12,4 @@ SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 # for libraries and headers in the target directories
 SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+SET(FDISK_BIN /usr/local/Cellar/util-linux/2.38_1/sbin/fdisk)

+ 4 - 4
include/asm/sys.h

@@ -7,17 +7,17 @@
 extern "C" {
 #endif
 
-void asm_switch_pd(page_directory_entry* pd_addr);
-void asm_enable_paging(page_directory_entry* pd_addr);
+void asm_switch_pd(pd_t pd_addr);
+void asm_enable_paging(pd_t pd_addr);
 
-phys_ptr_t current_pd(void);
+pptr_t current_pd(void);
 
 // the limit should be set on the higher 16bit
 // e.g. (n * sizeof(segment_descriptor) - 1) << 16
 // the lower bit off the limit is either 0 or 1
 // indicating whether or not to enable interrupt
 // after loading gdt
-void asm_load_gdt(uint32_t limit, phys_ptr_t addr);
+void asm_load_gdt(uint32_t limit, pptr_t addr);
 
 void asm_load_tr(uint16_t index);
 

+ 1 - 0
include/kernel/errno.h

@@ -21,3 +21,4 @@ extern uint32_t* _get_errno(void);
 #define EISDIR (1 << 4)
 #define ENOTDIR (1 << 5)
 #define ENOTFOUND (1 << 6)
+#define ECHILD (1 << 7)

+ 45 - 0
include/kernel/event/evtqueue.hpp

@@ -0,0 +1,45 @@
+#pragma once
+
+#include <types/list.hpp>
+#include <types/lock.hpp>
+
+// declaration in kernel/process.hpp
+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*>;
+
+private:
+    types::mutex m_mtx;
+    evt_list_type m_evts;
+    subscriber_list_type m_subscribers;
+
+public:
+    evtqueue(void) = default;
+    evtqueue(const evtqueue&) = delete;
+    evtqueue(evtqueue&&);
+
+    void push(evt&& event);
+    evt&& front();
+    const evt* peek(void) const;
+
+    bool empty(void) const;
+    void notify(void);
+
+    void subscribe(thread* thd);
+    void unsubscribe(thread* thd);
+};
+
+} // namespace kernel

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

@@ -57,5 +57,5 @@ public:
     int write_sector(const char* buf, uint32_t lba_low, uint16_t lba_high) const;
 };
 
-void init_ata(void* data);
+void init_ata(void);
 } // namespace hw

+ 8 - 4
include/kernel/hw/port.hpp

@@ -22,11 +22,13 @@ public:
             "this type is not implemented yet.");
         port_size_t ret;
         if constexpr (types::is_same<port_size_t, uint8_t>::value)
-            asm("inb %1, %0"
+            asm volatile(
+                "inb %1, %0"
                 : "=a"(ret)
                 : "d"(mp));
         if constexpr (types::is_same<port_size_t, uint16_t>::value)
-            asm("inw %1, %0"
+            asm volatile(
+                "inw %1, %0"
                 : "=a"(ret)
                 : "d"(mp));
         return ret;
@@ -38,11 +40,13 @@ public:
             types::is_same<port_size_t, uint8_t>::value || types::is_same<port_size_t, uint16_t>::value,
             "this type is not implemented yet.");
         if constexpr (types::is_same<port_size_t, uint8_t>::value)
-            asm("outb %1, %0"
+            asm volatile(
+                "outb %1, %0"
                 :
                 : "d"(mp), "a"(n));
         if constexpr (types::is_same<port_size_t, uint16_t>::value)
-            asm("outw %1, %0"
+            asm volatile(
+                "outw %1, %0"
                 :
                 : "d"(mp), "a"(n));
         return n;

+ 9 - 9
include/kernel/interrupt.h

@@ -27,8 +27,8 @@ struct PACKED interrupt_stack {
     void* v_eip;
     uint32_t cs;
     uint32_t eflags;
-    const uint32_t esp;
-    const uint32_t ss;
+    uint32_t esp;
+    uint32_t ss;
 };
 
 // present: When set, the page fault was caused by a page-protection violation.
@@ -56,15 +56,15 @@ struct page_fault_error_code {
     SET_IDT_ENTRY(0x20 + (N), (addr_irq##N), (SELECTOR), KERNEL_INTERRUPT_GATE_TYPE);
 
 #define SET_IDT_ENTRY_FN(N, FUNC_NAME, SELECTOR, TYPE) \
-    extern void FUNC_NAME();                     \
-    ptr_t addr_##FUNC_NAME = (ptr_t)FUNC_NAME;   \
+    extern void FUNC_NAME();                           \
+    ptr_t addr_##FUNC_NAME = (ptr_t)FUNC_NAME;         \
     SET_IDT_ENTRY((N), (addr_##FUNC_NAME), (SELECTOR), (TYPE));
 
-#define SET_IDT_ENTRY(N, ADDR, SELECTOR, TYPE)      \
-    IDT[(N)].offset_low = (ADDR)&0x0000ffff;  \
-    IDT[(N)].selector = (SELECTOR);           \
-    IDT[(N)].zero = 0;                        \
-    IDT[(N)].type_attr = (TYPE); \
+#define SET_IDT_ENTRY(N, ADDR, SELECTOR, TYPE) \
+    IDT[(N)].offset_low = (ADDR)&0x0000ffff;   \
+    IDT[(N)].selector = (SELECTOR);            \
+    IDT[(N)].zero = 0;                         \
+    IDT[(N)].type_attr = (TYPE);               \
     IDT[(N)].offset_high = ((ADDR)&0xffff0000) >> 16
 
 struct IDT_entry {

+ 32 - 34
include/kernel/mem.h

@@ -40,23 +40,22 @@ struct e820_mem_map_entry_24 {
  * ps  : use 4MiB pages (ignored)
  * addr: page table address
  */
-struct page_directory_entry_in {
-    uint32_t p : 1;
-    uint32_t rw : 1;
-    uint32_t us : 1;
-    uint32_t pwt : 1;
-    uint32_t pcd : 1;
-    uint32_t a : 1;
-    uint32_t d : 1;
-    uint32_t ps : 1;
-    uint32_t ignored : 4;
-    page_t pt_page : 20;
-};
-
-typedef union page_directory_entry {
+typedef union pde_t {
     uint32_t v;
-    struct page_directory_entry_in in;
-} page_directory_entry;
+    struct {
+        uint32_t p : 1;
+        uint32_t rw : 1;
+        uint32_t us : 1;
+        uint32_t pwt : 1;
+        uint32_t pcd : 1;
+        uint32_t a : 1;
+        uint32_t d : 1;
+        uint32_t ps : 1;
+        uint32_t ignored : 4;
+        page_t pt_page : 20;
+    } in;
+} pde_t;
+typedef pde_t (*pd_t)[1024];
 
 /*
  * page table entry
@@ -72,24 +71,23 @@ typedef union page_directory_entry {
  * g   : used in cr4 mode (ignored)
  * addr: physical memory address
  */
-struct page_table_entry_in {
-    uint32_t p : 1;
-    uint32_t rw : 1;
-    uint32_t us : 1;
-    uint32_t pwt : 1;
-    uint32_t pcd : 1;
-    uint32_t a : 1;
-    uint32_t d : 1;
-    uint32_t pat : 1;
-    uint32_t g : 1;
-    uint32_t ignored : 3;
-    page_t page : 20;
-};
-
-typedef union page_table_entry {
+typedef union pte_t {
     uint32_t v;
-    struct page_table_entry_in in;
-} page_table_entry;
+    struct {
+        uint32_t p : 1;
+        uint32_t rw : 1;
+        uint32_t us : 1;
+        uint32_t pwt : 1;
+        uint32_t pcd : 1;
+        uint32_t a : 1;
+        uint32_t d : 1;
+        uint32_t pat : 1;
+        uint32_t g : 1;
+        uint32_t ignored : 3;
+        page_t page : 20;
+    } in;
+} pte_t;
+typedef pte_t (*pt_t)[1024];
 
 // in kernel_main.c
 extern uint8_t e820_mem_map[1024];
@@ -109,7 +107,7 @@ void* ki_malloc(size_t size);
 
 void ki_free(void* ptr);
 
-#define KERNEL_PAGE_DIRECTORY_ADDR ((page_directory_entry*)0x00000000)
+#define KERNEL_PAGE_DIRECTORY_ADDR ((pd_t)0x00001000)
 
 void init_mem(void);
 

+ 280 - 80
include/kernel/mm.hpp

@@ -3,130 +3,330 @@
 #include <kernel/mem.h>
 #include <kernel/vfs.hpp>
 #include <types/allocator.hpp>
+#include <types/cplusplus.hpp>
 #include <types/list.hpp>
+#include <types/size.h>
+#include <types/status.h>
 #include <types/types.h>
 #include <types/vector.hpp>
 
-constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
+#define invalidate_tlb(addr) asm("invlpg (%0)" \
+                                 :             \
+                                 : "r"(addr)   \
+                                 : "memory")
 
-struct page_attr {
-    uint32_t cow : 1;
-};
+constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
 
 struct page {
     page_t phys_page_id;
+    pte_t* pte;
     size_t* ref_count;
-    struct page_attr attr;
+    union {
+        uint32_t v;
+        struct {
+            uint32_t cow : 1;
+        } in;
+    } attr;
 };
 
+// private memory mapping
+// changes won't be neither written back to file nor shared between processes
+// TODO: shared mapping
+// @param len is aligned to 4kb boundary automatically, exceeding part will
+// be filled with '0's and not written back to the file
+int mmap(
+    void* hint,
+    size_t len,
+    fs::inode* file,
+    size_t offset,
+    int write,
+    int priv);
+
 using page_arr = types::vector<page, types::kernel_ident_allocator>;
 
-struct mm_attr {
-    uint32_t read : 1;
-    uint32_t write : 1;
-    uint32_t system : 1;
-};
+// 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);
 
-class mm {
+void dealloc_pd(pd_t pd);
+void dealloc_pt(pt_t pt);
+
+// forward declaration
+namespace kernel {
+class mm_list;
+} // namespace kernel
+
+struct mm {
 public:
-    linr_ptr_t start;
-    struct mm_attr attr;
-    page_directory_entry* pd;
-    page_arr* pgs;
-    fs::inode* mapped_file;
-    size_t file_offset;
+    void* start;
+    union {
+        uint32_t v;
+        struct {
+            uint32_t read : 1;
+            uint32_t write : 1;
+            uint32_t system : 1;
+        } in;
+    } attr;
+    kernel::mm_list* owner;
+    page_arr* pgs = nullptr;
+    fs::inode* mapped_file = nullptr;
+    size_t file_offset = 0;
 
 public:
-    mm(const mm& val);
-    mm(linr_ptr_t start, page_directory_entry* pd, bool write, bool system);
+    constexpr void* end(void) const
+    {
+        return (char*)this->start + this->pgs->size() * PAGE_SIZE;
+    }
+
+    inline bool is_ident(void) const
+    {
+        return this->end() <= (void*)0x40000000U;
+    }
+
+    constexpr bool is_avail(void* start, void* end) const
+    {
+        void* m_start = this->start;
+        void* m_end = this->end();
+
+        return (start >= m_end || end <= m_start);
+    }
+
+    int append_page(page* pg, bool present, bool write, bool priv, bool cow);
 };
 
-using mm_list = types::list<mm, types::kernel_ident_allocator>;
+namespace kernel {
 
-// in mem.cpp
-extern mm_list* kernel_mms;
-extern page empty_page;
+class mm_list {
+public:
+    using list_type = ::types::list<mm, types::kernel_ident_allocator>;
+    using iterator_type = list_type::iterator_type;
+    using const_iterator_type = list_type::const_iterator_type;
 
-// translate physical address to virtual(mapped) address
-void* p_ptr_to_v_ptr(phys_ptr_t p_ptr);
+private:
+    list_type m_areas;
+
+public:
+    pd_t m_pd;
+
+public:
+    explicit constexpr mm_list(pd_t pd)
+        : m_pd(pd)
+    {
+    }
+    mm_list(const mm_list& v);
+    constexpr mm_list(mm_list&& v)
+        : m_areas(::types::move(v.m_areas))
+        , m_pd(v.m_pd)
+    {
+        v.m_pd = nullptr;
+    }
+    constexpr ~mm_list()
+    {
+        if (!m_pd)
+            return;
+
+        this->clear_user();
+        dealloc_pd(m_pd);
+    }
+
+    constexpr iterator_type begin(void)
+    {
+        return m_areas.begin();
+    }
+    constexpr iterator_type end(void)
+    {
+        return m_areas.end();
+    }
+    constexpr const_iterator_type begin(void) const
+    {
+        return m_areas.begin();
+    }
+    constexpr const_iterator_type end(void) const
+    {
+        return m_areas.end();
+    }
+    constexpr const_iterator_type cbegin(void) const
+    {
+        return m_areas.cbegin();
+    }
+    constexpr const_iterator_type cend(void) const
+    {
+        return m_areas.cend();
+    }
+
+    constexpr iterator_type addarea(void* start, bool w, bool system)
+    {
+        return m_areas.emplace_back(mm {
+            .start = start,
+            .attr {
+                .in {
+                    .read = 1,
+                    .write = w,
+                    .system = system,
+                },
+            },
+            .owner = this,
+            .pgs = ::types::kernel_ident_allocator_new<page_arr>(),
+        });
+    }
+
+    constexpr void clear_user()
+    {
+        for (auto iter = this->begin(); iter != this->end();) {
+            if (iter->is_ident()) {
+                ++iter;
+                continue;
+            }
 
-// translate linear address to physical address
-phys_ptr_t l_ptr_to_p_ptr(const mm_list* mms, linr_ptr_t v_ptr);
+            this->unmap(iter);
+            iter = m_areas.erase(iter);
+        }
+    }
 
-// translate virtual(mapped) address to physical address
-phys_ptr_t v_ptr_to_p_ptr(void* v_ptr);
+    constexpr int mirror_area(mm& src)
+    {
+        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;
+        }
 
-// @return the pointer to the mm_area containing l_ptr
-//         nullptr if not
-mm* find_mm_area(mm_list* mms, linr_ptr_t l_ptr);
+        for (auto& pg : *src.pgs) {
+            if (area->append_page(&pg,
+                    true,
+                    src.attr.in.write,
+                    src.attr.in.system,
+                    true)
+                != GB_OK) {
+                return GB_FAILED;
+            }
+        }
 
-// find the corresponding page the l_ptr pointing to
-// @return the pointer to the struct if found, NULL if not found
-struct page* find_page_by_l_ptr(const mm_list* mms, linr_ptr_t l_ptr);
+        return GB_OK;
+    }
 
-static inline page_t phys_addr_to_page(phys_ptr_t ptr)
+    constexpr void unmap(iterator_type area)
+    {
+        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;
+            }
+
+            pg.phys_page_id = 0;
+            pg.attr.v = 0;
+            pg.pte->v = 0;
+        }
+        area->attr.v = 0;
+        area->start = 0;
+    }
+
+    constexpr iterator_type find(void* lp)
+    {
+        for (auto iter = this->begin(); iter != this->end(); ++iter)
+            if (lp >= iter->start && lp < iter->end())
+                return iter;
+
+        return this->end();
+    }
+};
+
+} // namespace kernel
+
+// global variables
+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;
 }
-
-static inline pd_i_t page_to_pd_i(page_t p)
+inline constexpr size_t to_pdi(page_t pg)
 {
-    return p >> 10;
+    return pg >> 10;
 }
-
-static inline pt_i_t page_to_pt_i(page_t p)
+inline constexpr size_t to_pti(page_t pg)
 {
-    return p & (1024 - 1);
+    return pg & (1024 - 1);
 }
-
-static inline phys_ptr_t page_to_phys_addr(page_t p)
+inline constexpr pptr_t to_pp(page_t p)
 {
     return p << 12;
 }
-
-static inline pd_i_t linr_addr_to_pd_i(linr_ptr_t ptr)
+inline constexpr size_t lto_pdi(pptr_t ptr)
 {
-    return page_to_pd_i(phys_addr_to_page(ptr));
+    return to_pdi(to_page(ptr));
 }
-
-static inline pd_i_t linr_addr_to_pt_i(linr_ptr_t ptr)
+inline constexpr size_t lto_pti(pptr_t ptr)
 {
-    return page_to_pt_i(phys_addr_to_page(ptr));
+    return to_pti(to_page(ptr));
 }
-
-static inline page_directory_entry* mms_get_pd(const mm_list* mms)
+inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
 {
-    return mms->begin()->pd;
+    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);
 }
-
-// map the page to the end of the mm_area in pd
-int k_map(
-    mm* mm_area,
-    const struct page* page,
-    int read,
-    int write,
-    int priv,
-    int cow);
-
-// @param len is aligned to 4kb boundary automatically, exceeding part will
-// be filled with '0's and not written back to the file
-int mmap(
-    void* hint,
-    size_t len,
-    fs::inode* file,
-    size_t offset,
-    int write,
-    int priv);
 
 // allocate a raw page
-page_t alloc_raw_page(void);
-
-// allocate n raw page(s)
-// @return the id of the first page allocated
-page_t alloc_n_raw_pages(size_t n);
+inline page_t alloc_raw_page(void)
+{
+    return alloc_n_raw_pages(1);
+}
 
 // allocate a struct page together with the raw page
 struct page allocate_page(void);
-
-page_directory_entry* alloc_pd(void);
-page_table_entry* alloc_pt(void);

+ 96 - 25
include/kernel/process.hpp

@@ -1,12 +1,13 @@
 #pragma once
 
+#include <kernel/event/evtqueue.hpp>
 #include <kernel/interrupt.h>
-#include <kernel/task.h>
-#include <types/types.h>
-
-#ifdef __cplusplus
 #include <kernel/mm.hpp>
+#include <kernel/task.h>
+#include <types/hash_map.hpp>
 #include <types/list.hpp>
+#include <types/stdint.h>
+#include <types/types.h>
 
 typedef size_t pid_t;
 
@@ -15,6 +16,7 @@ struct thread;
 
 struct process_attr {
     uint16_t system : 1;
+    uint16_t zombie : 1 = 0;
 };
 
 struct thread_attr {
@@ -24,48 +26,117 @@ struct thread_attr {
 };
 
 struct thread {
-    void* eip;
+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);
+    }
+
+public:
+    uint32_t* esp;
+    pptr_t kstack;
     process* owner;
-    regs_32 regs;
-    uint32_t eflags;
     thread_attr attr;
+
+    explicit inline thread(process* _owner, bool system)
+        : owner { _owner }
+        , attr {
+            .system = system,
+            .ready = 1,
+            .wait = 0,
+        }
+    {
+        alloc_kstack();
+    }
+
+    constexpr thread(thread&& val)
+        : esp { val.esp }
+        , kstack { val.kstack }
+        , owner { val.owner }
+        , attr { val.attr }
+    {
+        val.attr = {};
+        val.esp = 0;
+        val.kstack = 0;
+        val.owner = nullptr;
+    }
+
+    inline thread(const thread& val)
+        : owner { val.owner }
+        , attr { val.attr }
+    {
+        alloc_kstack();
+    }
+
+    constexpr ~thread()
+    {
+        if (kstack)
+            free_n_raw_pages(to_page(kstack), 2);
+    }
 };
 
 class process {
 public:
-    mm_list mms;
+    mutable kernel::mm_list mms;
     types::list<thread> thds;
-    // TODO: allocate a kernel stack for EVERY THREAD
-    void* k_esp;
+    kernel::evtqueue wait_lst;
     process_attr attr;
     pid_t pid;
+    pid_t ppid;
 
 public:
     process(process&& val);
     process(const process&) = delete;
     process(const process& proc, const thread& main_thread);
-    process(void* start_eip, uint8_t* image, size_t image_size, bool system);
+
+    // only used for system initialization
+    explicit process(void);
+    explicit process(void (*func_in_kernel_space)(void), pid_t ppid);
+
+    ~process();
+
+private:
+    static inline pid_t max_pid;
+
+    static inline pid_t alloc_pid(void)
+    {
+        return ++max_pid;
+    }
 };
 
-// in process.cpp
-extern process* current_process;
-extern thread* current_thread;
+constexpr uint32_t push_stack(uint32_t** stack, uint32_t val)
+{
+    --*stack;
+    **stack = val;
+    return val;
+}
+
+inline process* volatile current_process;
+inline thread* volatile current_thread;
+inline typename types::hash_map<pid_t, types::list<pid_t>, types::linux_hasher<pid_t>>* idx_child_processes;
 
 extern "C" void NORETURN init_scheduler();
-void do_scheduling(interrupt_stack* intrpt_data);
+void schedule(void);
 
-void thread_context_save(interrupt_stack* int_stack, thread* thd);
-void thread_context_load(interrupt_stack* int_stack, thread* thd);
-void process_context_save(interrupt_stack*, process*);
-void process_context_load(interrupt_stack*, process* proc);
+pid_t add_to_process_list(process&& proc);
+void remove_from_process_list(pid_t pid);
 
-void add_to_process_list(process&& proc);
 void add_to_ready_list(thread* thd);
+void remove_from_ready_list(thread* thd);
+types::list<thread*>::iterator_type query_next_thread(void);
 
-void k_new_thread(void(*func)(void*), void* data);
-
-#else
+// the function call INVALIDATES iterator
+inline void next_task(types::list<thread*>::iterator_type target)
+{
+    auto* ptr = *target;
+    remove_from_ready_list(ptr);
+    if (ptr->attr.ready)
+        add_to_ready_list(ptr);
+}
 
-void NORETURN init_scheduler();
+process* findproc(pid_t pid);
 
-#endif
+void k_new_thread(void (*func)(void*), void* data);

+ 1 - 3
include/kernel/syscall.hpp

@@ -1,11 +1,9 @@
 #pragma once
 
-#include <types/types.h>
 #include <kernel/interrupt.h>
+#include <types/types.h>
 
 // return value is stored in %eax and %edx
 typedef void (*syscall_handler)(interrupt_stack* data);
 
-#define syscall(eax) asm volatile("movl %0, %%eax\n\tint $0x80"::"r"(eax):"eax","edx")
-
 void init_syscall(void);

+ 0 - 7
include/kernel_main.h

@@ -1,13 +1,6 @@
 #pragma once
 #include <types/types.h>
 
-static inline void __break_point(void)
-{
-    asm volatile("xchgw %bx, %bx");
-}
-
-#define MAKE_BREAK_POINT() __break_point()
-
 #define KERNEL_STACK_SIZE (16 * 1024)
 #define KERNEL_STACK_SEGMENT (0x10)
 

+ 48 - 7
include/types/allocator.hpp

@@ -1,6 +1,7 @@
 #pragma once
 #include <kernel/mem.h>
 #include <types/cplusplus.hpp>
+#include <types/stdint.h>
 #include <types/types.h>
 
 inline void* operator new(size_t, void* ptr)
@@ -10,7 +11,19 @@ inline void* operator new(size_t, void* ptr)
 
 namespace types {
 
-template <typename Allocator>
+template <typename T>
+concept Allocator = requires(size_t size, typename T::value_type* ptr)
+{
+    typename T::value_type;
+    {
+        T::allocate_memory(size)
+        } -> same_as<typename T::value_type*>;
+    {
+        T::deallocate_memory(ptr)
+        } -> same_as<void>;
+};
+
+template <Allocator T>
 class allocator_traits;
 
 template <typename T>
@@ -46,27 +59,55 @@ public:
 };
 
 template <typename T, typename... Args>
-T* kernel_allocator_new(Args&&... args)
+constexpr T* kernel_allocator_new(Args&&... args)
 {
     return allocator_traits<kernel_allocator<T>>::allocate_and_construct(forward<Args>(args)...);
 }
 
+template <PointerType T, typename... Args>
+constexpr auto kernel_allocator_pnew(T, Args&&... args)
+{
+    using value_type = typename traits::remove_pointer<T>::type;
+    return kernel_allocator_new<value_type>(forward<Args>(args)...);
+}
+
 template <typename T, typename... Args>
-T* kernel_ident_allocator_new(Args&&... args)
+constexpr T* kernel_ident_allocator_new(Args&&... args)
 {
     return allocator_traits<kernel_ident_allocator<T>>::allocate_and_construct(forward<Args>(args)...);
 }
 
-template <typename Allocator>
+template <PointerType T, typename... Args>
+constexpr auto kernel_ident_allocator_pnew(T, Args&&... args)
+{
+    using value_type = typename traits::remove_pointer<T>::type;
+    return kernel_ident_allocator_new<value_type>(forward<Args>(args)...);
+}
+
+template <PointerType T>
+constexpr void kernel_allocator_delete(T ptr)
+{
+    using value_type = typename traits::remove_pointer<T>::type;
+    return allocator_traits<kernel_allocator<value_type>>::deconstruct_and_deallocate(ptr);
+}
+
+template <PointerType T>
+constexpr void kernel_ident_allocator_delete(T ptr)
+{
+    using value_type = typename traits::remove_pointer<T>::type;
+    return allocator_traits<kernel_ident_allocator<value_type>>::deconstruct_and_deallocate(ptr);
+}
+
+template <Allocator _allocator>
 class allocator_traits {
 public:
-    using value_type = typename Allocator::value_type;
+    using value_type = typename _allocator::value_type;
 
     static value_type* allocate(size_t count)
     {
         if (count == 0)
             return nullptr;
-        return Allocator::allocate_memory(sizeof(value_type) * count);
+        return _allocator::allocate_memory(sizeof(value_type) * count);
     }
 
     template <typename... Args>
@@ -95,7 +136,7 @@ public:
     {
         if (!ptr)
             return;
-        Allocator::deallocate_memory(ptr);
+        _allocator::deallocate_memory(ptr);
     }
 
     static void deconstruct_and_deallocate(value_type* ptr)

+ 40 - 0
include/types/assert.h

@@ -0,0 +1,40 @@
+#pragma once
+
+#include "types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void crash(void);
+void _debugger_breakpoint(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef NDEBUG
+#define breakpoint() _debugger_breakpoint()
+#else
+#define breakpoint() _crash()
+#endif
+
+#ifndef NDEBUG
+
+#define assert(_statement) \
+    if (!(_statement)) {   \
+        breakpoint();      \
+        crash();           \
+    }
+
+#define assert_likely(_statement)  \
+    if (unlikely(!(_statement))) { \
+        breakpoint();              \
+        crash();                   \
+    }
+
+#else
+
+#define assert(_statement) ;
+
+#endif

+ 46 - 9
include/types/cplusplus.hpp

@@ -1,7 +1,20 @@
 #pragma once
 
+#include <types/stdint.h>
+
 #ifdef __cplusplus
 
+namespace types {
+
+template <typename T, T _value>
+struct constant_value {
+    static constexpr T value = _value;
+};
+using true_type = constant_value<bool, true>;
+using false_type = constant_value<bool, false>;
+
+};
+
 namespace types::traits::inner {
 
 template <typename Tp, typename>
@@ -65,6 +78,14 @@ struct remove_cv<const volatile T> {
     using type = T;
 };
 
+template <typename T>
+struct is_pointer : false_type {
+};
+
+template <typename T>
+struct is_pointer<T*> : true_type {
+};
+
 template <typename T>
 struct decay {
 private:
@@ -78,23 +99,16 @@ public:
 
 namespace types {
 template <typename T>
-T&& move(T& val)
+constexpr T&& move(T& val)
 {
     return static_cast<T&&>(val);
 }
 template <typename T>
-T&& forward(typename traits::remove_reference<T>::type& val)
+constexpr T&& forward(typename traits::remove_reference<T>::type& val)
 {
     return static_cast<T&&>(val);
 }
 
-template <typename T, T _value>
-struct constant_value {
-    static constexpr T value = _value;
-};
-using true_type = constant_value<bool, true>;
-using false_type = constant_value<bool, false>;
-
 template <typename>
 struct template_true_type : public true_type {
 };
@@ -110,6 +124,29 @@ template <typename T>
 struct is_same<T, T> : true_type {
 };
 
+template <typename T>
+struct add_rvalue_reference {
+    using type = T&&;
+};
+template <>
+struct add_rvalue_reference<void> {
+    using type = void;
+};
+
+template <typename Src, typename Dst>
+concept convertible_to = (traits::is_pointer<Src>::value && is_same<Dst, uint32_t>::value)
+    || (traits::is_pointer<Dst>::value && is_same<Src, uint32_t>::value)
+    || requires(Src _src)
+{
+    { static_cast<Dst>(_src) };
+};
+
+template <typename T>
+concept PointerType = traits::is_pointer<T>::value;
+
+template <typename A, typename B>
+concept same_as = is_same<A, B>::value;
+
 } // namespace types
 
 #endif

+ 124 - 0
include/types/elf.hpp

@@ -0,0 +1,124 @@
+#pragma once
+#include <kernel/errno.h>
+#include <kernel/interrupt.h>
+#include <kernel/process.hpp>
+#include <kernel/vfs.hpp>
+#include <types/size.h>
+#include <types/status.h>
+#include <types/stdint.h>
+
+namespace types::elf {
+using elf32_addr_t = uint32_t;
+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_off_t ELF_STACK_SIZE = 8 * 1024 * 1024;
+constexpr elf32_addr_t ELF_STACK_TOP = ELF_STACK_BOTTOM - ELF_STACK_SIZE;
+
+struct PACKED elf32_header {
+    // 0x7f, "ELF"
+    char magic[4];
+
+    enum : uint8_t {
+        FORMAT_32 = 1,
+        FORMAT_64 = 2,
+    } format;
+    enum : uint8_t {
+        ENDIAN_LITTLE = 1,
+        ENDIAN_BIG = 2,
+    } endian;
+    // should be 1
+    uint8_t _version1;
+    enum : uint8_t {
+        ABI_SYSTEM_V = 0x00,
+        // TODO:
+        ABI_LINUX = 0x03,
+    } abi;
+    uint8_t abi_version;
+    uint8_t _reserved[7];
+    enum : uint16_t {
+        ET_NONE = 0x00,
+        ET_REL = 0x01,
+        ET_EXEC = 0x02,
+        ET_DYN = 0x03,
+        ET_CORE = 0x04,
+        ET_LOOS = 0xfe00,
+        ET_HIOS = 0xfeff,
+        ET_LOPROC = 0xff00,
+        ET_HIPROC = 0xffff,
+    } type;
+    enum : uint16_t {
+        ARCH_NONE = 0x00,
+        ARCH_X86 = 0x03,
+        ARCH_ARM = 0x28,
+        ARCH_IA64 = 0x32,
+        ARCH_X86_64 = 0x3e,
+        ARCH_ARM64 = 0xb7,
+        ARCH_RISCV = 0xf3,
+    } arch;
+    // should be 1
+    uint32_t _version2;
+    // entry address
+    elf32_addr_t entry;
+    // program header table offset
+    elf32_off_t phoff;
+    // section header table offset
+    elf32_off_t shoff;
+    // architecture dependent flags
+    uint32_t flags;
+    // elf header size
+    uint16_t ehsize;
+    // program header table entry size
+    uint16_t phentsize;
+    // program header table entries number
+    uint16_t phnum;
+    // section header table entry size
+    uint16_t shentsize;
+    // section header table entries number
+    uint16_t shnum;
+    // section header table entry index that contains section names
+    uint16_t shstrndx;
+};
+
+struct PACKED elf32_program_header_entry {
+    enum : uint32_t {
+        PT_NULL = 0x00,
+        PT_LOAD = 0x01,
+        PT_DYNAMIC = 0x02,
+        PT_INTERP = 0x03,
+        PT_NOTE = 0x04,
+        PT_SHLIB = 0x05,
+        PT_PHDR = 0x06,
+        PT_TLS = 0x07,
+        PT_LOOS = 0x60000000,
+        PT_HIOS = 0x6fffffff,
+        PT_LIPROC = 0x70000000,
+        PT_HIPROC = 0x7fffffff,
+    } type;
+    elf32_off_t offset;
+    elf32_addr_t vaddr;
+    elf32_addr_t paddr;
+    elf32_off_t filesz;
+    elf32_off_t memsz;
+    // segment dependent
+    uint32_t flags;
+    // 0 and 1 for no alignment, otherwise power of 2
+    uint32_t align;
+};
+
+struct elf32_load_data {
+    const char* exec;
+    const char** argv;
+    int errcode;
+    void* eip;
+    uint32_t* sp;
+    bool system;
+};
+
+// TODO: environment variables
+int elf32_load(elf32_load_data* data);
+
+} // namespace types::elf

+ 60 - 48
include/types/hash_map.hpp

@@ -14,28 +14,29 @@ namespace types {
 constexpr uint32_t GOLDEN_RATIO_32 = 0x61C88647;
 // constexpr uint64_t GOLDEN_RATIO_64 = 0x61C8864680B583EBull;
 
-static constexpr uint32_t _hash32(uint32_t val)
+using hash_t = size_t;
+
+static inline constexpr hash_t _hash32(uint32_t val)
 {
     return val * GOLDEN_RATIO_32;
 }
 
-static constexpr uint32_t hash32(uint32_t val, uint32_t bits)
+static inline constexpr hash_t hash32(uint32_t val, uint32_t bits)
 {
     // higher bits are more random
     return _hash32(val) >> (32 - bits);
 }
 
-template <typename T>
+template <convertible_to<uint32_t> T>
 struct linux_hasher {
-    static constexpr uint32_t hash(const T& val, uint32_t bits)
+    static inline constexpr hash_t hash(T val, uint32_t bits)
     {
-        return hash32(val, bits);
+        return hash32(static_cast<uint32_t>(val), bits);
     }
 };
-
 template <typename T>
 struct linux_hasher<T*> {
-    static constexpr uint32_t hash(T* val, uint32_t bits)
+    static inline constexpr hash_t hash(T* val, uint32_t bits)
     {
         return hash32(reinterpret_cast<uint32_t>(val), bits);
     }
@@ -43,15 +44,15 @@ struct linux_hasher<T*> {
 
 template <typename T>
 struct string_hasher {
-    static constexpr uint32_t hash(T, uint32_t)
+    static inline constexpr hash_t hash(T, uint32_t)
     {
         static_assert(types::template_false_type<T>::value, "string hasher does not support this type");
-        return (uint32_t)0;
+        return (hash_t)0;
     }
 };
 template <>
 struct string_hasher<const char*> {
-    static constexpr uint32_t hash(const char* str, uint32_t bits)
+    static inline constexpr hash_t hash(const char* str, uint32_t bits)
     {
         constexpr uint32_t seed = 131;
         uint32_t hash = 0;
@@ -64,7 +65,7 @@ struct string_hasher<const char*> {
 };
 template <template <typename> class Allocator>
 struct string_hasher<const types::string<Allocator>&> {
-    static inline constexpr uint32_t hash(const types::string<Allocator>& str, uint32_t bits)
+    static inline constexpr hash_t hash(const types::string<Allocator>& str, uint32_t bits)
     {
         return string_hasher<const char*>::hash(str.c_str(), bits);
     }
@@ -77,17 +78,15 @@ struct string_hasher<types::string<Allocator>&&> {
     }
 };
 
-template <class Hasher, typename Value>
-struct hasher_traits {
-    using hash_t = size_t;
-    using length_t = size_t;
-    static constexpr hash_t hash(Value val, length_t bits)
+template <typename _Hasher, typename Value>
+concept Hasher = requires(Value&& val, uint32_t bits)
+{
     {
-        return Hasher::hash(val, bits);
-    }
+        _Hasher::hash(val, bits)
+        } -> convertible_to<size_t>;
 };
 
-template <typename Key, typename Value, typename Hasher, template <typename _T> class Allocator = types::kernel_allocator>
+template <typename Key, typename Value, Hasher<Key> _Hasher, template <typename _T> class Allocator = types::kernel_allocator>
 class hash_map {
 public:
     struct pair;
@@ -112,13 +111,13 @@ public:
         const key_type key;
         value_type value;
 
-        pair(void) = delete;
-        pair(const key_type _key, value_type _val)
+        constexpr pair(void) = delete;
+        constexpr pair(const key_type _key, value_type _val)
             : key(_key)
             , value(_val)
         {
         }
-        bool operator==(const pair& p)
+        constexpr bool operator==(const pair& p)
         {
             return key == p.key;
         }
@@ -130,49 +129,51 @@ public:
         using _Value = typename traits::remove_pointer<Pointer>::type;
         using Reference = typename traits::add_reference<_Value>::type;
 
+        friend class hash_map;
+
     public:
-        iterator(const iterator& iter) noexcept
+        constexpr iterator(const iterator& iter) noexcept
             : p(iter.p)
         {
         }
 
-        iterator(iterator&& iter) noexcept
+        constexpr iterator(iterator&& iter) noexcept
             : p(iter.p)
         {
             iter.p = nullptr;
         }
 
-        iterator& operator=(const iterator& iter)
+        constexpr iterator& operator=(const iterator& iter)
         {
             p = iter.p;
             return *this;
         }
 
-        explicit iterator(Pointer p) noexcept
+        explicit constexpr iterator(Pointer p) noexcept
             : p(p)
         {
         }
 
-        bool operator==(const iterator& iter) noexcept
+        constexpr bool operator==(const iterator& iter) const noexcept
         {
             return this->p == iter.p;
         }
 
-        bool operator!=(const iterator& iter) noexcept
+        constexpr bool operator!=(const iterator& iter) const noexcept
         {
             return !(*this == iter);
         }
 
-        bool operator!()
+        constexpr operator bool()
         {
-            return !p;
+            return p != nullptr;
         }
 
-        Reference operator*() const noexcept
+        constexpr Reference operator*() const noexcept
         {
             return *p;
         }
-        Pointer operator->() const noexcept
+        constexpr Pointer operator->() const noexcept
         {
             return p;
         }
@@ -203,46 +204,46 @@ protected:
     }
 
 public:
-    explicit hash_map(void)
+    explicit constexpr hash_map(void)
         : buckets(INITIAL_BUCKETS_ALLOCATED)
     {
         for (size_type i = 0; i < INITIAL_BUCKETS_ALLOCATED; ++i)
             buckets.emplace_back();
     }
 
-    hash_map(const hash_map& v)
+    constexpr hash_map(const hash_map& v)
         : buckets(v.buckets)
     {
     }
 
-    hash_map(hash_map&& v)
+    constexpr hash_map(hash_map&& v)
         : buckets(move(v.buckets))
     {
     }
 
-    ~hash_map()
+    constexpr ~hash_map()
     {
         buckets.clear();
     }
 
-    void insert(const pair& p)
+    constexpr void insert(const pair& p)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(p.key, hash_length());
+        auto hash_value = _Hasher::hash(p.key, hash_length());
         buckets.at(hash_value).push_back(p);
     }
-    void insert(pair&& p)
+    constexpr void insert(pair&& p)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(p.key, hash_length());
+        auto hash_value = _Hasher::hash(p.key, hash_length());
         buckets.at(hash_value).push_back(move(p));
     }
-    void insert(const key_type& key, const value_type& val)
+    constexpr void insert(const key_type& key, const value_type& val)
     {
         insert(pair { key, val });
     }
 
-    void remove(const key_type& key)
+    constexpr void remove(const key_type& key)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(key, hash_length());
+        auto hash_value = _Hasher::hash(key, hash_length());
         auto& bucket = buckets.at(hash_value);
         for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
             if (iter->key == key) {
@@ -252,9 +253,20 @@ public:
         }
     }
 
-    iterator_type find(const key_type& key)
+    constexpr void remove(iterator_type iter)
+    {
+        remove(iter->key);
+        iter.p = nullptr;
+    }
+    constexpr void remove(const_iterator_type iter)
+    {
+        remove(iter->key);
+        iter.p = nullptr;
+    }
+
+    constexpr iterator_type find(const key_type& key)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(key, hash_length());
+        auto hash_value = _Hasher::hash(key, hash_length());
         auto& bucket = buckets.at(hash_value);
         for (auto& item : bucket) {
             if (key == item.key)
@@ -263,9 +275,9 @@ public:
         return iterator_type(nullptr);
     }
 
-    const_iterator_type find(const key_type& key) const
+    constexpr const_iterator_type find(const key_type& key) const
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(key, hash_length());
+        auto hash_value = _Hasher::hash(key, hash_length());
         const auto& bucket = buckets.at(hash_value);
         for (const auto& item : bucket) {
             if (key == item.key)
@@ -274,7 +286,7 @@ public:
         return const_iterator_type(nullptr);
     }
 
-    void clear(void)
+    constexpr void clear(void)
     {
         for (size_t i = 0; i < buckets.size(); ++i)
             buckets.at(i).clear();

+ 46 - 45
include/types/list.hpp

@@ -36,7 +36,7 @@ private:
         node_type* prev = 0;
         node_type* next = 0;
 
-        void connect(node_type* _next) noexcept
+        constexpr void connect(node_type* _next) noexcept
         {
             this->next = _next;
             _next->prev = static_cast<node_type*>(this);
@@ -46,12 +46,12 @@ private:
     template <typename NodeValue>
     class node : public node_base {
     public:
-        explicit node(const NodeValue& v) noexcept
+        explicit constexpr node(const NodeValue& v) noexcept
             : value(v)
         {
         }
 
-        explicit node(NodeValue&& v) noexcept
+        explicit constexpr node(NodeValue&& v) noexcept
             : value(move(v))
         {
         }
@@ -67,80 +67,80 @@ public:
         using Reference = typename types::traits::add_reference<Value>::type;
 
     public:
-        iterator(const iterator& iter) noexcept
+        constexpr iterator(const iterator& iter) noexcept
             : n(iter.n)
         {
         }
 
-        iterator(iterator&& iter) noexcept
+        constexpr iterator(iterator&& iter) noexcept
             : n(iter.n)
         {
             iter.n = nullptr;
         }
 
-        iterator& operator=(const iterator& iter)
+        constexpr iterator& operator=(const iterator& iter)
         {
             n = iter.n;
             return *this;
         }
 
-        explicit iterator(node_type* _n) noexcept
+        explicit constexpr iterator(node_type* _n) noexcept
             : n(_n)
         {
         }
 
-        bool operator==(const iterator& iter) noexcept
+        constexpr bool operator==(const iterator& iter) const noexcept
         {
             return this->_node() == iter._node();
         }
 
-        bool operator!=(const iterator& iter) noexcept
+        constexpr bool operator!=(const iterator& iter) const noexcept
         {
             return !(*this == iter);
         }
 
-        iterator& operator++() noexcept
+        constexpr iterator& operator++() noexcept
         {
             n = n->next;
             return *this;
         }
 
-        iterator operator++(int) noexcept
+        constexpr iterator operator++(int) noexcept
         {
             iterator iter(*this);
             n = n->next;
             return iter;
         }
 
-        iterator& operator--() noexcept
+        constexpr iterator& operator--() noexcept
         {
             n = n->prev;
             return *this;
         }
 
-        iterator operator--(int) noexcept
+        constexpr iterator operator--(int) noexcept
         {
             iterator iter(*this);
             n = n->prev;
             return iter;
         }
 
-        Reference operator*() const noexcept
+        constexpr Reference operator*() const noexcept
         {
             return n->value;
         }
 
-        Pointer operator->() const noexcept
+        constexpr Pointer operator->() const noexcept
         {
             return &n->value;
         }
 
-        Pointer ptr(void) const noexcept
+        constexpr Pointer ptr(void) const noexcept
         {
             return &n->value;
         }
 
-        node_base_type* _node(void) const noexcept
+        constexpr node_base_type* _node(void) const noexcept
         {
             return n;
         }
@@ -153,17 +153,17 @@ private:
     node_base_type* head;
     node_base_type* tail;
 
-    const size_t& _size(void) const noexcept
+    constexpr const size_t& _size(void) const noexcept
     {
         return (static_cast<sentry_node_type*>(head))->value;
     }
 
-    size_t& _size(void) noexcept
+    constexpr size_t& _size(void) noexcept
     {
         return (static_cast<sentry_node_type*>(head))->value;
     }
 
-    void destroy(void)
+    constexpr void destroy(void)
     {
         if (!head || !tail)
             return;
@@ -173,7 +173,7 @@ private:
     }
 
 public:
-    list() noexcept
+    constexpr list() noexcept
         // size is stored in the 'head' node
         : head(allocator_traits<sentry_allocator_type>::allocate_and_construct(0))
         , tail(allocator_traits<sentry_allocator_type>::allocate_and_construct(0))
@@ -182,14 +182,14 @@ public:
         tail->connect(static_cast<node_type*>(head));
     }
 
-    list(const list& v)
+    constexpr list(const list& v)
         : list()
     {
         for (const auto& item : v)
             push_back(item);
     }
 
-    list(list&& v)
+    constexpr list(list&& v)
         : head(v.head)
         , tail(v.tail)
     {
@@ -197,7 +197,7 @@ public:
         v.tail = nullptr;
     }
 
-    list& operator=(const list& v)
+    constexpr list& operator=(const list& v)
     {
         clear();
         for (const auto& item : v)
@@ -205,7 +205,7 @@ public:
         return *this;
     }
 
-    list& operator=(list&& v)
+    constexpr list& operator=(list&& v)
     {
         destroy();
 
@@ -217,20 +217,21 @@ public:
         return *this;
     }
 
-    ~list() noexcept
+    constexpr ~list() noexcept
     {
         destroy();
     }
 
-    iterator_type find(const value_type& v) noexcept
+    constexpr iterator_type find(const value_type& v) noexcept
     {
         for (iterator_type iter = begin(); iter != end(); ++iter)
             if (*iter == v)
                 return iter;
+        return end();
     }
 
     // erase the node which iter points to
-    iterator_type erase(const iterator_type& iter) noexcept
+    constexpr iterator_type erase(const iterator_type& iter) noexcept
     {
         node_base_type* current_node = iter._node();
         iterator_type ret(current_node->next);
@@ -240,14 +241,14 @@ public:
         return ret;
     }
 
-    void clear(void)
+    constexpr void clear(void)
     {
         for (auto iter = begin(); iter != end();)
             iter = erase(iter);
     }
 
     // insert the value v in front of the given iterator
-    iterator_type insert(const iterator_type& iter, const value_type& v) noexcept
+    constexpr iterator_type insert(const iterator_type& iter, const value_type& v) noexcept
     {
         node_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(v);
         iterator_type ret(new_node);
@@ -259,7 +260,7 @@ public:
     }
 
     // insert the value v in front of the given iterator
-    iterator_type insert(const iterator_type& iter, value_type&& v) noexcept
+    constexpr iterator_type insert(const iterator_type& iter, value_type&& v) noexcept
     {
         node_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(move(v));
         iterator_type ret(new_node);
@@ -270,74 +271,74 @@ public:
         return ret;
     }
 
-    void push_back(const value_type& v) noexcept
+    constexpr void push_back(const value_type& v) noexcept
     {
         insert(end(), v);
     }
 
-    void push_back(value_type&& v) noexcept
+    constexpr void push_back(value_type&& v) noexcept
     {
         insert(end(), move(v));
     }
 
     template <typename... Args>
-    iterator_type emplace_back(Args&&... args)
+    constexpr iterator_type emplace_back(Args&&... args)
     {
         return insert(end(), value_type(forward<Args>(args)...));
     }
 
-    void push_front(const value_type& v) noexcept
+    constexpr void push_front(const value_type& v) noexcept
     {
         insert(begin(), v);
     }
 
-    void push_front(value_type&& v) noexcept
+    constexpr void push_front(value_type&& v) noexcept
     {
         insert(begin(), move(v));
     }
 
     template <typename... Args>
-    iterator_type emplace_front(Args&&... args)
+    constexpr iterator_type emplace_front(Args&&... args)
     {
         return insert(begin(), value_type(forward<Args>(args)...));
     }
 
-    size_t size(void) const noexcept
+    constexpr size_t size(void) const noexcept
     {
         return _size();
     }
 
-    iterator_type begin() noexcept
+    constexpr iterator_type begin() noexcept
     {
         return iterator_type(head->next);
     }
 
-    iterator_type end() noexcept
+    constexpr iterator_type end() noexcept
     {
         return iterator_type(static_cast<node_type*>(tail));
     }
 
-    const_iterator_type begin() const noexcept
+    constexpr const_iterator_type begin() const noexcept
     {
         return const_iterator_type(head->next);
     }
 
-    const_iterator_type end() const noexcept
+    constexpr const_iterator_type end() const noexcept
     {
         return const_iterator_type(static_cast<node_type*>(tail));
     }
 
-    const_iterator_type cbegin() const noexcept
+    constexpr const_iterator_type cbegin() const noexcept
     {
         return begin();
     }
 
-    const_iterator_type cend() const noexcept
+    constexpr const_iterator_type cend() const noexcept
     {
         return end();
     }
 
-    bool empty(void) const noexcept
+    constexpr bool empty(void) const noexcept
     {
         return size() == 0;
     }

+ 0 - 35
include/types/lock.h

@@ -1,35 +0,0 @@
-#pragma once
-
-#include <types/stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static inline void spin_lock(uint32_t volatile* lock_addr)
-{
-    asm volatile(
-            "_spin:\n\t\
-             movl $1, %%eax\n\t\
-             xchgl %%eax, (%0)\n\t\
-             test $0, %%eax\n\t\
-             jne _spin\n\t\
-            "
-            : "=r" (lock_addr)
-            : "0"  (lock_addr)
-            : "eax", "memory"
-            );
-}
-
-static inline void spin_unlock(uint32_t volatile* lock_addr)
-{
-    asm volatile("movl $0, %%eax\nxchgl %%eax, (%0)"
-                 :
-                 : "r"  (lock_addr)
-                 : "eax", "memory"
-                 );
-}
-
-#ifdef __cplusplus
-}
-#endif

+ 67 - 0
include/types/lock.hpp

@@ -0,0 +1,67 @@
+#pragma once
+
+#include <types/stdint.h>
+
+inline void spin_lock(uint32_t volatile* lock_addr)
+{
+    asm volatile(
+        "0:\n\t\
+         movl $1, %%eax\n\t\
+         xchgl %%eax, (%0)\n\t\
+         test $0, %%eax\n\t\
+         jne 0\n\t\
+        "
+        :
+        : "r"(lock_addr)
+        : "eax", "memory");
+}
+
+inline void spin_unlock(uint32_t volatile* lock_addr)
+{
+    asm volatile(
+        "movl $0, %%eax\n\
+         xchgl %%eax, (%0)"
+        :
+        : "r"(lock_addr)
+        : "eax", "memory");
+}
+
+namespace types {
+
+struct mutex {
+    using mtx_t = volatile uint32_t;
+
+    mtx_t m_lock = 0;
+
+    inline void lock(void)
+    {
+        spin_lock(&m_lock);
+    }
+
+    inline void unlock(void)
+    {
+        spin_unlock(&m_lock);
+    }
+};
+
+class lock_guard {
+private:
+    mutex& m_mtx;
+
+public:
+    explicit lock_guard(mutex& mtx)
+        : m_mtx(mtx)
+    {
+        mtx.lock();
+    }
+
+    lock_guard(const lock_guard&) = delete;
+    lock_guard(lock_guard&&) = delete;
+
+    ~lock_guard()
+    {
+        m_mtx.unlock();
+    }
+};
+
+} // namespace types

+ 1 - 4
include/types/size.h

@@ -18,8 +18,5 @@ typedef uint64_t ptr_t;
 typedef int64_t diff_t;
 #endif
 
-typedef ptr_t phys_ptr_t;
-typedef ptr_t linr_ptr_t;
+typedef ptr_t pptr_t;
 typedef size_t page_t;
-typedef size_t pd_i_t;
-typedef size_t pt_i_t;

+ 17 - 17
include/types/string.hpp

@@ -17,17 +17,17 @@ public:
     static inline constexpr size_type npos = (-1U);
 
 public:
-    explicit string(size_type capacity = 8)
+    explicit constexpr string(size_type capacity = 8)
         : inner_vector_type(capacity)
     {
         this->push_back(0x00);
     }
-    string(const char* str, size_type n = npos)
+    constexpr string(const char* str, size_type n = npos)
         : string()
     {
         this->append(str, n);
     }
-    string& append(const char* str, size_type n = npos)
+    constexpr string& append(const char* str, size_type n = npos)
     {
         this->pop_back();
 
@@ -39,51 +39,51 @@ public:
         this->push_back(0x00);
         return *this;
     }
-    string& append(const string& str)
+    constexpr string& append(const string& str)
     {
         return this->append(str.data());
     }
-    string& append(string&& str)
+    constexpr string& append(string&& str)
     {
         return this->append(str.data());
     }
-    string& operator+=(const char c)
+    constexpr string& operator+=(const char c)
     {
         this->pop_back();
         this->push_back(c);
         this->push_back(0x00);
         return *this;
     }
-    string& operator+=(const char* str)
+    constexpr string& operator+=(const char* str)
     {
         return this->append(str);
     }
-    string& operator+=(const string& str)
+    constexpr string& operator+=(const string& str)
     {
         return this->append(str);
     }
-    string& operator+=(string&& str)
+    constexpr string& operator+=(string&& str)
     {
         return this->append(move(str));
     }
-    bool operator==(const string& rhs) const
+    constexpr bool operator==(const string& rhs) const
     {
         return strcmp(c_str(), rhs.c_str()) == 0;
     }
-    string substr(size_type pos, size_type n = npos)
+    constexpr string substr(size_type pos, size_type n = npos)
     {
         return string(this->m_arr + pos, n);
     }
-    const char* c_str(void) const noexcept
+    constexpr const char* c_str(void) const noexcept
     {
         return this->data();
     }
-    void clear(void)
+    constexpr void clear(void)
     {
         inner_vector_type::clear();
         this->push_back(0x00);
     }
-    char pop(void)
+    constexpr char pop(void)
     {
         this->pop_back();
         auto iter = inner_vector_type::back();
@@ -91,21 +91,21 @@ public:
         *iter = 0x00;
         return c;
     }
-    typename inner_vector_type::iterator_type back(void)
+    constexpr typename inner_vector_type::iterator_type back(void)
     {
         // TODO: assert
         if (this->empty())
             return typename inner_vector_type::iterator_type((void*)0xffffffff);
         return --inner_vector_type::back();
     }
-    typename inner_vector_type::const_iterator_type back(void) const
+    constexpr typename inner_vector_type::const_iterator_type back(void) const
     {
         // TODO: assert
         if (this->empty())
             return typename inner_vector_type::iterator_type((void*)0xffffffff);
         return --inner_vector_type::back();
     }
-    typename inner_vector_type::const_iterator_type cback(void) const
+    constexpr typename inner_vector_type::const_iterator_type cback(void) const
     {
         // TODO: assert
         if (this->empty())

+ 8 - 0
include/types/types.h

@@ -18,6 +18,14 @@
 #error "no definition for ((SECTION))"
 #endif
 
+#ifdef __GNUC__
+#define likely(expr) (__builtin_expect(!!(expr), 1))
+#define unlikely(expr) (__builtin_expect(!!(expr), 0))
+#else
+#define likely(expr) (!!(expr))
+#define unlikely(expr) (!!(expr))
+#endif
+
 #ifdef __cplusplus
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>

+ 46 - 46
include/types/vector.hpp

@@ -30,82 +30,82 @@ public:
         using Reference = typename types::traits::add_reference<Value>::type;
 
     public:
-        iterator(const iterator& iter) noexcept
+        constexpr iterator(const iterator& iter) noexcept
             : p(iter.p)
         {
         }
 
-        iterator(iterator&& iter) noexcept
+        constexpr iterator(iterator&& iter) noexcept
             : p(iter.p)
         {
             iter.p = nullptr;
         }
 
-        iterator& operator=(const iterator& iter)
+        constexpr iterator& operator=(const iterator& iter)
         {
             p = iter.p;
             return *this;
         }
 
-        explicit iterator(Pointer p) noexcept
+        explicit constexpr iterator(Pointer p) noexcept
             : p(p)
         {
         }
 
-        bool operator==(const iterator& iter) noexcept
+        constexpr bool operator==(const iterator& iter) const noexcept
         {
             return this->p == iter.p;
         }
 
-        bool operator!=(const iterator& iter) noexcept
+        constexpr bool operator!=(const iterator& iter) const noexcept
         {
             return !(*this == iter);
         }
 
-        iterator& operator++() noexcept
+        constexpr iterator& operator++() noexcept
         {
             ++p;
             return *this;
         }
 
-        iterator operator++(int) noexcept
+        constexpr iterator operator++(int) noexcept
         {
             iterator iter(*this);
             ++p;
             return iter;
         }
 
-        iterator& operator--() noexcept
+        constexpr iterator& operator--() noexcept
         {
             --p;
             return *this;
         }
 
-        iterator operator--(int) noexcept
+        constexpr iterator operator--(int) noexcept
         {
             iterator iter(*this);
             --p;
             return iter;
         }
 
-        iterator operator+(size_type n) noexcept
+        constexpr iterator operator+(size_type n) noexcept
         {
             iterator iter(p + n);
             return iter;
         }
 
-        iterator operator-(size_type n) noexcept
+        constexpr iterator operator-(size_type n) noexcept
         {
             iterator iter(p - n);
             return iter;
         }
 
-        Reference operator*() const noexcept
+        constexpr Reference operator*() const noexcept
         {
             return *p;
         }
 
-        Pointer operator->() const noexcept
+        constexpr Pointer operator->() const noexcept
         {
             return p;
         }
@@ -115,21 +115,21 @@ public:
     };
 
 public:
-    explicit vector(size_type capacity = 1) noexcept
+    explicit constexpr vector(size_type capacity = 1) noexcept
         : m_arr(nullptr)
         , m_size(0)
     {
         resize(capacity);
     }
 
-    vector(const vector& arr) noexcept
+    constexpr vector(const vector& arr) noexcept
         : vector(arr.capacity())
     {
         for (const auto& item : arr)
             push_back(item);
     }
 
-    vector(vector&& arr) noexcept
+    constexpr vector(vector&& arr) noexcept
     {
         m_arr = arr.m_arr;
         m_capacity = arr.m_capacity;
@@ -140,7 +140,7 @@ public:
         arr.m_size = 0;
     }
 
-    vector& operator=(vector&& arr)
+    constexpr vector& operator=(vector&& arr)
     {
         resize(0);
         m_arr = arr.m_arr;
@@ -154,17 +154,17 @@ public:
         return *this;
     }
 
-    vector& operator=(const vector& arr)
+    constexpr vector& operator=(const vector& arr)
     {
         return operator=(vector(arr));
     }
 
-    ~vector() noexcept
+    constexpr ~vector() noexcept
     {
         resize(0);
     }
 
-    void resize(size_type n)
+    constexpr void resize(size_type n)
     {
         value_type* new_ptr = allocator_traits<allocator_type>::allocate(n);
 
@@ -213,39 +213,39 @@ public:
     //     ++_size();
     // }
 
-    value_type* data(void) noexcept
+    constexpr value_type* data(void) noexcept
     {
         return m_arr;
     }
 
-    const value_type* data(void) const noexcept
+    constexpr const value_type* data(void) const noexcept
     {
         return m_arr;
     }
 
-    value_type& at(index_type i) noexcept
+    constexpr value_type& at(index_type i) noexcept
     {
         // TODO: boundary check
         return _at(i);
     }
 
-    const value_type& at(index_type i) const noexcept
+    constexpr const value_type& at(index_type i) const noexcept
     {
         // TODO: boundary check
         return _at(i);
     }
 
-    value_type& operator[](index_type i) noexcept
+    constexpr value_type& operator[](index_type i) noexcept
     {
         return at(i);
     }
 
-    const value_type& operator[](index_type i) const noexcept
+    constexpr const value_type& operator[](index_type i) const noexcept
     {
         return at(i);
     }
 
-    void push_back(const value_type& v) noexcept
+    constexpr void push_back(const value_type& v) noexcept
     {
         if (m_size == m_capacity)
             resize(m_capacity * 2);
@@ -253,7 +253,7 @@ public:
         ++m_size;
     }
 
-    void push_back(value_type&& v) noexcept
+    constexpr void push_back(value_type&& v) noexcept
     {
         if (m_size == m_capacity)
             resize(m_capacity * 2);
@@ -262,74 +262,74 @@ public:
     }
 
     template <typename... Args>
-    iterator_type emplace_back(Args&&... args)
+    constexpr iterator_type emplace_back(Args&&... args)
     {
         push_back(value_type(forward<Args>(args)...));
         return back();
     }
 
-    void pop_back(void) noexcept
+    constexpr void pop_back(void) noexcept
     {
         allocator_traits<allocator_type>::deconstruct(&*back());
         --m_size;
     }
 
-    size_type size(void) const noexcept
+    constexpr size_type size(void) const noexcept
     {
         return m_size;
     }
 
-    size_type capacity(void) const noexcept
+    constexpr size_type capacity(void) const noexcept
     {
         return m_capacity;
     }
 
-    const_iterator_type cbegin() const noexcept
+    constexpr const_iterator_type cbegin() const noexcept
     {
         return const_iterator_type(m_arr);
     }
 
-    const_iterator_type cend() const noexcept
+    constexpr const_iterator_type cend() const noexcept
     {
         return const_iterator_type(m_arr + m_size);
     }
 
-    iterator_type begin() noexcept
+    constexpr iterator_type begin() noexcept
     {
         return iterator_type(m_arr);
     }
 
-    const_iterator_type begin() const noexcept
+    constexpr const_iterator_type begin() const noexcept
     {
         return cbegin();
     }
 
-    iterator_type end() noexcept
+    constexpr iterator_type end() noexcept
     {
         return iterator_type(m_arr + m_size);
     }
 
-    const_iterator_type end() const noexcept
+    constexpr const_iterator_type end() const noexcept
     {
         return cend();
     }
 
-    iterator_type back() noexcept
+    constexpr iterator_type back() noexcept
     {
         return iterator_type(m_arr + m_size - 1);
     }
 
-    const_iterator_type back() const noexcept
+    constexpr const_iterator_type back() const noexcept
     {
         return const_iterator_type(m_arr + m_size - 1);
     }
 
-    bool empty(void) const noexcept
+    constexpr bool empty(void) const noexcept
     {
         return size() == 0;
     }
 
-    void clear(void)
+    constexpr void clear(void)
     {
         for (size_t i = 0; i < size(); ++i)
             allocator_traits<allocator_type>::deconstruct(m_arr + i);
@@ -345,17 +345,17 @@ public:
     // iterator_type cr_end() noexcept;
 
 protected:
-    inline const value_type& _at(index_type i) const
+    inline constexpr const value_type& _at(index_type i) const
     {
         return m_arr[i];
     }
-    inline value_type& _at(index_type i)
+    inline constexpr value_type& _at(index_type i)
     {
         return m_arr[i];
     }
 
 protected:
-    value_type* m_arr;
+    T* m_arr;
     size_type m_capacity;
     size_type m_size;
 };

+ 73 - 0
pretty-print.py

@@ -0,0 +1,73 @@
+import gdb.printing
+
+def create_iter(item, end, idx):
+    return vectorPrinter._iterator(item, end, idx)
+
+class vectorPrinter:
+    class _iterator:
+        def __init__(self, item, end, idx):
+            self.item = item
+            self.end = end
+            self.size = self.end - self.item
+            self.idx = idx
+
+        def __iter__(self):
+            return self
+
+        def __next__(self):
+            if self.item >= self.end:
+                raise StopIteration
+            key = '[%d]' % self.idx
+            iter = self.item.dereference()
+            self.item += 1
+            self.idx += 1
+            return key, iter
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return "vector of size %d, capacity %d" % (self.val['m_size'], self.val['m_capacity'])
+
+    def display_hint(self):
+        return 'array'
+
+    def children(self):
+        return self._iterator(self.val['m_arr'], self.val['m_arr'] + self.val['m_size'], 0)
+
+class stringPrinter:
+    def __init__(self, val):
+        self.val = val
+    
+    def to_string(self):
+        return self.val['m_arr']
+
+class listPrinter:
+    def __init__(self, val):
+        self.val = val
+    
+    def to_string(self):
+        return "list of size %d" % (self.val['head'].reinterpret_cast(gdb.lookup_type("size_t").pointer()) + 2).dereference()
+
+    def display_hint(self):
+        return 'array'
+
+    def children(self):
+        node = self.val['head']['next']
+        end = self.val['tail']
+        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
+
+gdb.printing.register_pretty_printer(
+        gdb.current_objfile(),
+        build_pretty_printer())

+ 12 - 1
src/asm/a20.s

@@ -7,9 +7,20 @@ check_a20_on:
     pushal
     movl $0x112345, %edi
     movl $0x012345, %esi
+
+    movl (%esi), %eax
+    movl (%edi), %ecx
+
     movl %esi, (%esi)
     movl %edi, (%edi)
-    cmpsd
+    cmpsl
+
+    subl $4, %esi
+    subl $4, %edi
+
+    movl %eax, (%esi)
+    movl %ecx, (%edi)
+
     popal
     jne a20_on
     movl $0, %eax

+ 68 - 45
src/asm/interrupt.s

@@ -215,15 +215,54 @@ syscall_stub:
     # restore stack
     popl %esp
 
+.globl _syscall_stub_fork_return
+.type  _syscall_stub_fork_return @function
+_syscall_stub_fork_return:
     popal
 syscall_stub_end:
     iret
 
-# parameters:
-# interrupt_stack* ret_stack
-.globl to_kernel
-.type  to_kernel @function
-to_kernel:
+# parameters
+# #1: uint32_t* curr_esp
+# #2: uint32_t next_esp
+.globl asm_ctx_switch
+.type  asm_ctx_switch @function
+asm_ctx_switch:
+    movl 4(%esp), %ecx
+    movl 8(%esp), %eax
+
+    push $_ctx_switch_return
+    push %ebx
+    push %edi
+    push %esi
+    push %ebp
+    pushfl
+
+    movl %esp, (%ecx)
+    movl %eax, %esp
+
+    popfl
+    pop %ebp
+    pop %esi
+    pop %edi
+    pop %ebx
+
+    ret
+
+_ctx_switch_return:
+    ret
+
+# param:
+# #1: uint32_t esp
+# #2: void (*k_init)()
+.globl go_kernel
+.type  go_kernel @function
+go_kernel:
+    movl 4(%esp), %eax
+    movl 8(%esp), %ecx
+    movl %eax, %esp
+    pushl %ecx
+
     movw $0x10, %ax
     movw %ax, %ss
     movw %ax, %ds
@@ -231,55 +270,39 @@ to_kernel:
     movw %ax, %fs
     movw %ax, %gs
 
-    movl 4(%esp), %eax
-
-    movl (%eax), %edi
-    movl 4(%eax), %esi
-    movl 8(%eax), %ebp
-    movl 12(%eax), %esp # %esp is the dst stack
-    movl 16(%eax), %ebx
-    movl 20(%eax), %edx
-    movl 24(%eax), %ecx
-#   TODO: optimize for caching
-#   movl 28(%eax), %eax # we deal with %eax later
+    xorl %eax, %eax
+    xorl %ebx, %ebx
+    xorl %ecx, %ecx
+    xorl %edx, %edx
+    xorl %esi, %esi
+    xorl %edi, %edi
+    xorl %ebp, %ebp
 
-    pushl 40(%eax) # %eflags
-    pushl $0x08    # %cs
-    pushl 32(%eax) # %eip
+# eflags: IN
+    pushl $0x200
+    popfl
 
-    movl 28(%eax), %eax
-
-    iret
+    ret
 
-# parameters:
-# interrupt_stack* ret_stack
-.globl to_user
-.type  to_user @function
-to_user:
+# parameters
+# #1: eip
+# #2: esp
+.globl go_user
+.type  go_user @function
+go_user:
     movw $0x23, %ax
     movw %ax, %ds
     movw %ax, %es
     movw %ax, %fs
     movw %ax, %gs
 
-    movl 4(%esp), %edi
-
-    movl 40(%edi), %ebp # save eflags
-    movl 32(%edi), %esi # save eip
-
-    movl 28(%edi), %eax
-    movl 24(%edi), %ecx
-    movl 20(%edi), %edx
-    movl 16(%edi), %ebx
-
-    pushl $0x23    # %ss
-    pushl 12(%edi) # %esp
-    pushl %ebp     # %eflags
-    pushl $0x1b    # %cs
-    pushl %esi     # %eip
+    movl 4(%esp), %eax
+    movl 8(%esp), %ecx
 
-    movl 8(%edi), %ebp
-    movl 4(%edi), %esi
-    movl (%edi), %edi
+    pushl $0x23
+    pushl %ecx
+    pushl $0x200
+    pushl $0x1b
+    pushl %eax
 
     iret

+ 3 - 1
src/asm/port_io.s

@@ -45,9 +45,11 @@ asm_sti:
 .type  asm_enable_sse @function
 asm_enable_sse:
 	movl %cr0, %eax
-	orl $0b10, %eax
+    andl $0xfffffff3, %eax
+	orl $0b100010, %eax
 	movl %eax, %cr0
 	movl %cr4, %eax
 	orl $0b11000000000, %eax
 	movl %eax, %cr4
+    fninit
 	ret

+ 0 - 22
src/asm/sys.s

@@ -52,25 +52,3 @@ asm_load_tr:
     orl $0, %eax
     ltr %ax
     ret
-
-.globl go_user_space
-.type  go_user_space @function
-go_user_space:
-    movl $((4 * 8) | 3), %eax
-    movw %ax, %ds
-    movw %ax, %es
-    movw %ax, %fs
-    movw %ax, %gs
-
-    movl 4(%esp), %ebx
-    pushl $((4 * 8) | 3)
-    pushl $0x40100000
-    pushf
-    # allow interrupts in user mode
-    movl (%esp), %eax
-    orl $0x200, %eax
-    movl %eax, (%esp)
-    pushl $((3 * 8) | 3)
-    pushl %ebx
-
-    iret

+ 10 - 10
src/boot.s

@@ -111,37 +111,37 @@ setup_early_kernel_page_table:
 # set up early kernel page table
 
 # the early kernel page directory is located at physical
-# address 0x00000000, size 4k, and the empty page is at
-# 0x5000-0x5fff, so we fill the first 6KiB
+# address 0x00001000, size 4k, and the empty page is at
+# 0x0000-0x0fff, so we fill the first 6KiB
     movl $0x00000000, %eax
     movl $0x6000, %ecx
     call _fill_zero
 
 # map the first 16MiB identically
-# 0x0000-0x0fff: early kernel pd
-# 0x1000-0x4fff: pde 0 - 4
-    movl $0x00000000, %eax
-    movl $0x00001003, %ebx
+# 0x1000-0x1fff: early kernel pd
+# 0x2000-0x5fff: pde 0 - 4
+    movl $0x00001000, %eax
+    movl $0x00002003, %ebx
 _fill_pde_loop:
     movl %ebx, (%eax)
     addl $4, %eax
     addl $0x1000, %ebx
-    cmpl $0x5003, %ebx
+    cmpl $0x6003, %ebx
     jne _fill_pde_loop
 
 # then, create page tables
     movl $0x00000003, %eax
-    movl $0x00001000, %ecx
+    movl $0x00002000, %ecx
 
 _create_page_table_loop1:
     movl %eax, (%ecx)
     addl $4, %ecx
     addl $0x1000, %eax
-    cmpl $0x4ffc, %ecx
+    cmpl $0x5ffc, %ecx
     jle _create_page_table_loop1
 
 load_early_kernel_page_table:
-    movl $0x00000000, %eax
+    movl $0x00001000, %eax
     movl %eax, %cr3
 
     movl %cr0, %eax

+ 8 - 10
src/fs/fat.cpp

@@ -1,9 +1,9 @@
 #include <fs/fat.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
-#include <kernel/syscall.hpp>
 #include <kernel/vfs.hpp>
 #include <types/allocator.hpp>
+#include <types/assert.h>
 #include <types/hash_map.hpp>
 #include <types/status.h>
 #include <types/stdint.h>
@@ -12,15 +12,13 @@ namespace fs::fat {
 // buf MUST be larger than 512 bytes
 inline void fat32::read_sector(void* buf, uint32_t sector_no)
 {
-    if (vfs_read(
-            device,
-            (char*)buf,
-            SECTOR_SIZE,
-            sector_no * SECTOR_SIZE,
-            SECTOR_SIZE)
-        != SECTOR_SIZE) {
-        syscall(0x03);
-    }
+    assert(vfs_read(
+               device,
+               (char*)buf,
+               SECTOR_SIZE,
+               sector_no * SECTOR_SIZE,
+               SECTOR_SIZE)
+        == SECTOR_SIZE);
 }
 
 // buf MUST be larger than 4096 bytes

+ 3 - 0
src/kernel.ld

@@ -38,6 +38,9 @@ SECTIONS
         KEEP(*(SORT_BY_INIT_PRIORITY(.ctors*)));
         end_ctors = .;
 
+        __stack_chk_guard = .;
+        LONG(0x19198101);
+
         *(.data)
         *(.data*)
         __kernel_text_and_data_end = .;

+ 58 - 0
src/kernel/event/event.cpp

@@ -1,10 +1,15 @@
 #include <asm/port_io.h>
 #include <kernel/event/event.h>
+#include <kernel/event/evtqueue.hpp>
 #include <kernel/input/input_event.h>
+#include <kernel/process.hpp>
 #include <kernel/stdio.h>
 #include <kernel/tty.h>
 #include <types/allocator.hpp>
+#include <types/assert.h>
+#include <types/cplusplus.hpp>
 #include <types/list.hpp>
+#include <types/lock.hpp>
 
 static ::types::list<::input_event>* _input_event_queue;
 
@@ -40,3 +45,56 @@ void dispatch_event(void)
         }
     }
 }
+
+kernel::evtqueue::evtqueue(evtqueue&& q)
+    : m_evts { types::move(q.m_evts) }
+    , m_subscribers { types::move(q.m_subscribers) }
+{
+}
+
+void kernel::evtqueue::push(kernel::evt&& event)
+{
+    types::lock_guard lck(m_mtx);
+    m_evts.push_back(types::move(event));
+    this->notify();
+}
+
+kernel::evt&& kernel::evtqueue::front()
+{
+    assert(!this->empty());
+    types::lock_guard lck(m_mtx);
+
+    auto iter = m_evts.begin();
+    evt e = types::move(*iter);
+    m_evts.erase(iter);
+    return types::move(e);
+}
+
+const kernel::evt* kernel::evtqueue::peek(void) const
+{
+    return m_evts.begin().ptr();
+}
+
+bool kernel::evtqueue::empty(void) const
+{
+    return m_evts.empty();
+}
+
+void kernel::evtqueue::notify(void)
+{
+    for (auto* sub : m_subscribers) {
+        sub->attr.ready = 1;
+        sub->attr.wait = 0;
+        add_to_ready_list(sub);
+    }
+}
+
+void kernel::evtqueue::subscribe(thread* thd)
+{
+    m_subscribers.push_back(thd);
+}
+
+void kernel::evtqueue::unsubscribe(thread* thd)
+{
+    m_subscribers.erase(m_subscribers.find(thd));
+}

+ 3 - 5
src/kernel/hw/ata.cpp

@@ -145,7 +145,7 @@ size_t _ata_read(fs::special_node* sn, char* buf, size_t buf_size, size_t offset
         end = sn->data1 + sn->data2;
     offset %= 512;
     for (size_t i = start; i < end; ++i) {
-        (*ata_bus)->read_sector(b, i, 0);
+        (void)(*ata_bus)->read_sector(b, i, 0);
         size_t to_copy = 0;
         if (offset)
             to_copy = 512 - offset;
@@ -196,11 +196,9 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
     }
 }
 
-void hw::init_ata(void* data)
+// data: void (*func_to_call_next)(void)
+void hw::init_ata(void)
 {
-    if (data != nullptr)
-        syscall(0x03);
-
     ata_pri = types::kernel_allocator_new<ata>(ATA_PRIMARY_BUS_BASE);
     if (ata_pri->identify())
         ata_pri->select(true);

+ 3 - 2
src/kernel/hw/serial.c

@@ -1,3 +1,4 @@
+#include <types/status.h>
 #include <asm/port_io.h>
 #include <kernel/hw/serial.h>
 #include <kernel/stdio.h>
@@ -21,7 +22,7 @@ int32_t init_serial_port(port_id_t port)
 
     // Check if serial is faulty (i.e: not same byte as sent)
     if (asm_inb(port + 0) != 0xAE) {
-        return 1;
+        return GB_FAILED;
     }
 
     // If serial is not faulty set it in normal operation mode
@@ -29,7 +30,7 @@ int32_t init_serial_port(port_id_t port)
     asm_outb(port + 4, 0x0F);
 
     asm_outb(port + 1, 0x01); // Enable interrupts #0: Received Data Available
-    return 0;
+    return GB_OK;
 }
 
 int32_t is_serial_has_data(port_id_t port)

+ 22 - 24
src/kernel/interrupt.cpp

@@ -14,8 +14,10 @@
 #include <kernel/vfs.hpp>
 #include <kernel/vga.h>
 #include <kernel_main.h>
+#include <types/assert.h>
 #include <types/size.h>
 #include <types/stdint.h>
+#include <types/types.h>
 
 static struct IDT_entry IDT[256];
 
@@ -141,7 +143,7 @@ extern "C" void int13_handler(
 }
 
 struct PACKED int14_data {
-    linr_ptr_t l_addr;
+    void* l_addr;
     struct regs_32 s_regs;
     struct page_fault_error_code error_code;
     void* v_eip;
@@ -149,46 +151,42 @@ struct PACKED int14_data {
     uint32_t eflags;
 };
 
-static inline void _int14_panic(void* eip, linr_ptr_t cr2, struct page_fault_error_code error_code)
+static inline void _int14_panic(void* eip, void* cr2, struct page_fault_error_code error_code)
 {
     char buf[256] {};
     snprintf(
         buf, 256,
         "\nkilled: segmentation fault (eip: %x, cr2: %x, error_code: %x)\n", eip, cr2, error_code);
     tty_print(console, buf);
-    MAKE_BREAK_POINT();
-    asm_cli();
-    asm_hlt();
+    assert(false);
 }
 
 // page fault
 extern "C" void int14_handler(int14_data* d)
 {
-    mm_list* mms = nullptr;
+    kernel::mm_list* mms = nullptr;
     if (current_process)
         mms = &current_process->mms;
     else
         mms = kernel_mms;
 
-    mm* mm_area = find_mm_area(mms, d->l_addr);
-    if (!mm_area)
+    auto mm_area = mms->find(d->l_addr);
+    if (unlikely(mm_area == mms->end()))
         _int14_panic(d->v_eip, d->l_addr, d->error_code);
 
-    page_directory_entry* pde = mms_get_pd(mms) + linr_addr_to_pd_i(d->l_addr);
-    page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
-    pte += linr_addr_to_pt_i(d->l_addr);
-    struct page* page = find_page_by_l_ptr(mms, d->l_addr);
+    pte_t* pte = to_pte(mms->m_pd, d->l_addr);
+    page* page = lto_page(mm_area.ptr(), d->l_addr);
 
-    if (d->error_code.present == 0 && !mm_area->mapped_file)
+    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.cow == 1) {
+    if (page->attr.in.cow == 1) {
         // if it is a dying page
         if (*page->ref_count == 1) {
-            page->attr.cow = 0;
+            page->attr.in.cow = 0;
             pte->in.a = 0;
-            pte->in.rw = mm_area->attr.write;
+            pte->in.rw = mm_area->attr.in.write;
             return;
         }
         // duplicate the page
@@ -198,33 +196,33 @@ extern "C" void int14_handler(int14_data* d)
         if (d->error_code.present == 0)
             pte->in.p = 1;
 
-        char* new_page_data = (char*)p_ptr_to_v_ptr(page_to_phys_addr(new_page));
-        memcpy(new_page_data, p_ptr_to_v_ptr(page_to_phys_addr(page->phys_page_id)), PAGE_SIZE);
+        char* new_page_data = (char*)to_vp(new_page);
+        memcpy(new_page_data, to_vp(page->phys_page_id), PAGE_SIZE);
 
         pte->in.page = new_page;
-        pte->in.rw = mm_area->attr.write;
+        pte->in.rw = mm_area->attr.in.write;
         pte->in.a = 0;
 
         --*page->ref_count;
 
-        page->ref_count = (size_t*)k_malloc(sizeof(size_t));
+        page->ref_count = (size_t*)ki_malloc(sizeof(size_t));
         *page->ref_count = 1;
-        page->attr.cow = 0;
+        page->attr.in.cow = 0;
         page->phys_page_id = new_page;
 
         // memory mapped
         if (d->error_code.present == 0) {
-            size_t offset = (d->l_addr - mm_area->start) & 0xfffff000;
+            size_t offset = vptrdiff(d->l_addr, mm_area->start) & 0xfffff000;
             vfs_read(mm_area->mapped_file, new_page_data, PAGE_SIZE, mm_area->file_offset + offset, PAGE_SIZE);
         }
     }
 }
 
-extern "C" void irq0_handler(struct interrupt_stack* d)
+extern "C" void irq0_handler(interrupt_stack*)
 {
     inc_tick();
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    do_scheduling(d);
+    schedule();
 }
 // keyboard interrupt
 extern "C" void irq1_handler(void)

+ 126 - 204
src/kernel/mem.cpp

@@ -9,19 +9,16 @@
 #include <kernel/task.h>
 #include <kernel/vga.h>
 #include <kernel_main.h>
+#include <types/allocator.hpp>
+#include <types/assert.h>
 #include <types/bitmap.h>
+#include <types/size.h>
 #include <types/status.h>
 
-// global objects
-
-mm_list* kernel_mms;
-
-// ---------------------
-
 // constant values
 
-#define EMPTY_PAGE_ADDR ((phys_ptr_t)0x5000)
-#define EMPTY_PAGE_END ((phys_ptr_t)0x6000)
+#define EMPTY_PAGE_ADDR ((pptr_t)0x0000)
+#define EMPTY_PAGE_END ((pptr_t)0x1000)
 
 #define IDENTICALLY_MAPPED_HEAP_SIZE ((size_t)0x400000)
 
@@ -59,9 +56,9 @@ private:
     brk_memory_allocator(const brk_memory_allocator&) = delete;
     brk_memory_allocator(brk_memory_allocator&&) = delete;
 
-    inline int brk(byte* addr)
+    inline constexpr int brk(byte* addr)
     {
-        if (addr >= p_limit)
+        if (unlikely(addr >= p_limit))
             return GB_FAILED;
         p_break = addr;
         return GB_OK;
@@ -70,7 +67,7 @@ private:
     // sets errno
     inline byte* sbrk(size_type increment)
     {
-        if (brk(p_break + increment) != GB_OK) {
+        if (unlikely(brk(p_break + increment) != GB_OK)) {
             errno = ENOMEM;
             return nullptr;
         } else {
@@ -99,7 +96,7 @@ private:
                 errno = 0;
                 return start_pos;
             } else {
-                if (!start_pos->flags.has_next) {
+                if (unlikely(!start_pos->flags.has_next)) {
                     errno = ENOTFOUND;
                     return start_pos;
                 }
@@ -113,7 +110,7 @@ private:
     {
         sbrk(sizeof(mem_blk) + size - 4 * sizeof(byte));
         // preserves errno
-        if (errno) {
+        if (unlikely(errno)) {
             return nullptr;
         }
 
@@ -200,7 +197,9 @@ static brk_memory_allocator
 
 void* k_malloc(size_t size)
 {
-    return kernel_heap_allocator->alloc(size);
+    void* ptr = kernel_heap_allocator->alloc(size);
+    assert_likely(ptr);
+    return ptr;
 }
 
 void k_free(void* ptr)
@@ -211,9 +210,7 @@ void k_free(void* ptr)
 void* ki_malloc(size_t size)
 {
     void* ptr = kernel_ident_mapped_allocator.alloc(size);
-    if (!ptr) {
-        MAKE_BREAK_POINT();
-    }
+    assert_likely(ptr);
     return ptr;
 }
 
@@ -222,85 +219,54 @@ void ki_free(void* ptr)
     kernel_ident_mapped_allocator.free(ptr);
 }
 
-void* p_ptr_to_v_ptr(phys_ptr_t p_ptr)
-{
-    if (p_ptr <= 0x30000000) {
-        // memory below 768MiB is identically mapped
-        return (void*)p_ptr;
-    } else {
-        // TODO: address translation
-        MAKE_BREAK_POINT();
-        return (void*)0xffffffff;
-    }
-}
-
-phys_ptr_t l_ptr_to_p_ptr(const mm_list* mms, linr_ptr_t v_ptr)
-{
-    for (const mm& item : *mms) {
-        if (v_ptr < item.start || v_ptr >= item.start + item.pgs->size() * PAGE_SIZE)
-            continue;
-        size_t offset = (size_t)(v_ptr - item.start);
-        const page& p = item.pgs->at(offset / PAGE_SIZE);
-        return page_to_phys_addr(p.phys_page_id) + (offset % PAGE_SIZE);
-    }
-
-    // TODO: handle error
-    return 0xffffffff;
-}
-
-phys_ptr_t v_ptr_to_p_ptr(const void* v_ptr)
+void* ptovp(pptr_t p_ptr)
 {
-    if (v_ptr < KERNEL_IDENTICALLY_MAPPED_AREA_LIMIT) {
-        return (phys_ptr_t)v_ptr;
-    }
-    return l_ptr_to_p_ptr(kernel_mms, (linr_ptr_t)v_ptr);
+    // memory below 768MiB is identically mapped
+    // TODO: address translation for high mem
+    assert(p_ptr <= 0x30000000);
+    return (void*)p_ptr;
 }
 
-static inline void mark_page(page_t n)
+inline void mark_page(page_t n)
 {
     bm_set(mem_bitmap, n);
 }
 
-static inline void free_page(page_t n)
+inline void free_page(page_t n)
 {
     bm_clear(mem_bitmap, n);
 }
 
-static void mark_addr_len(phys_ptr_t start, size_t n)
+constexpr void mark_addr_len(pptr_t start, size_t n)
 {
-    if (n == 0)
+    if (unlikely(n == 0))
         return;
-    page_t start_page = phys_addr_to_page(start);
-    page_t end_page = phys_addr_to_page(start + n + 4095);
+    page_t start_page = to_page(start);
+    page_t end_page = to_page(start + n + 4095);
     for (page_t i = start_page; i < end_page; ++i)
         mark_page(i);
 }
 
-static void free_addr_len(phys_ptr_t start, size_t n)
+constexpr void free_addr_len(pptr_t start, size_t n)
 {
-    if (n == 0)
+    if (unlikely(n == 0))
         return;
-    page_t start_page = phys_addr_to_page(start);
-    page_t end_page = phys_addr_to_page(start + n + 4095);
+    page_t start_page = to_page(start);
+    page_t end_page = to_page(start + n + 4095);
     for (page_t i = start_page; i < end_page; ++i)
         free_page(i);
 }
 
-static inline void mark_addr_range(phys_ptr_t start, phys_ptr_t end)
+inline constexpr void mark_addr_range(pptr_t start, pptr_t end)
 {
     mark_addr_len(start, end - start);
 }
 
-static inline void free_addr_range(phys_ptr_t start, phys_ptr_t end)
+inline constexpr void free_addr_range(pptr_t start, pptr_t end)
 {
     free_addr_len(start, end - start);
 }
 
-page_t alloc_raw_page(void)
-{
-    return alloc_n_raw_pages(1);
-}
-
 // @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)
 {
@@ -320,52 +286,75 @@ page_t alloc_n_raw_pages(size_t n)
             first += (max + 1);
         } else {
             for (page_t i = first; i < first + n; ++i)
-                bm_set(mem_bitmap, i);
+                mark_page(i);
             return first;
         }
     }
-    MAKE_BREAK_POINT();
+    assert(false);
     return 0xffffffff;
 }
 
-struct page allocate_page(void)
+void free_n_raw_pages(page_t start_pg, size_t n)
 {
-    struct page p { };
-    p.phys_page_id = alloc_raw_page();
-    p.ref_count = types::kernel_ident_allocator_new<size_t>(0);
-    return p;
+    while (n--)
+        free_page(start_pg++);
 }
 
-static inline void make_page_table(page_table_entry* pt)
+struct page allocate_page(void)
 {
-    memset(pt, 0x00, sizeof(page_table_entry) * 1024);
+    return page {
+        .phys_page_id = alloc_raw_page(),
+        .pte = nullptr,
+        .ref_count = types::kernel_ident_allocator_new<size_t>(0),
+        .attr { 0 },
+    };
 }
 
-page_directory_entry* alloc_pd(void)
+pd_t alloc_pd(void)
 {
     // TODO: alloc page in low mem and gen struct page for it
     page_t pd_page = alloc_raw_page();
-    page_directory_entry* pd = (page_directory_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pd_page));
+    pd_t pd = to_pd(pd_page);
     memset(pd, 0x00, PAGE_SIZE);
     return pd;
 }
 
-page_table_entry* alloc_pt(void)
+pt_t alloc_pt(void)
 {
     // TODO: alloc page in low mem and gen struct page for it
     page_t pt_page = alloc_raw_page();
-    page_table_entry* pt = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pt_page));
-    make_page_table(pt);
+    pt_t pt = to_pt(pt_page);
+    memset(pt, 0x00, PAGE_SIZE);
     return pt;
 }
 
+void dealloc_pd(pd_t pd)
+{
+    for (pde_t* ent = (*pd) + 256; ent < (*pd) + 1024; ++ent) {
+        if (!ent->in.p)
+            continue;
+        dealloc_pt(to_pt(ent));
+    }
+    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);
+}
+
 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(0x00000000, 0x00005000);
+    mark_addr_range(0x00001000, 0x00006000);
     // mark empty page
     mark_addr_range(EMPTY_PAGE_ADDR, EMPTY_PAGE_END);
     // mark EBDA and upper memory as allocated
@@ -392,86 +381,62 @@ static inline void init_mem_layout(void)
     }
 }
 
-mm* find_mm_area(mm_list* mms, linr_ptr_t l_ptr)
+using kernel::mm_list;
+mm_list::mm_list(const mm_list& v)
+    : m_areas(v.m_areas)
 {
-    for (auto iter = mms->begin(); iter != mms->end(); ++iter)
-        if (l_ptr >= iter->start && l_ptr < iter->start + iter->pgs->size() * PAGE_SIZE)
-            return iter.ptr();
-    return nullptr;
-}
-
-struct page* find_page_by_l_ptr(const mm_list* mms, linr_ptr_t l_ptr)
-{
-    for (const mm& item : *mms) {
-        if (l_ptr >= item.start && l_ptr < item.start + item.pgs->size() * PAGE_SIZE) {
-            size_t offset = (size_t)(l_ptr - item.start);
-            return &item.pgs->at(offset / PAGE_SIZE);
-        }
-    }
-
-    // TODO: error handling
-    return nullptr;
+    pd_t pd = alloc_pd();
+    memcpy(pd, v.m_pd, PAGE_SIZE);
+    m_pd = pd;
 }
 
-static inline void map_raw_page_to_pte(
-    page_table_entry* pte,
+inline void map_raw_page_to_pte(
+    pte_t* pte,
     page_t page,
-    int present,
-    int rw,
-    int priv)
+    bool present,
+    bool write,
+    bool priv)
 {
     // set P bit
     pte->v = 0;
     pte->in.p = present;
-    pte->in.rw = (rw == 1);
-    pte->in.us = (priv == 0);
+    pte->in.rw = write;
+    pte->in.us = !priv;
     pte->in.page = page;
 }
 
-// map page to the end of mm_area in pd
-int k_map(
-    mm* mm_area,
-    const struct page* page,
-    int read,
-    int write,
-    int priv,
-    int cow)
+int mm::append_page(page* pg, bool present, bool write, bool priv, bool cow)
 {
-    linr_ptr_t addr = (linr_ptr_t)mm_area->start + mm_area->pgs->size() * PAGE_SIZE;
-    page_directory_entry* pde = mm_area->pd + linr_addr_to_pd_i(addr);
+    void* addr = this->end();
+    pde_t* pde = to_pde(this->owner->m_pd, addr);
     // page table not exist
-    if (!pde->in.p) {
+    if (unlikely(!pde->in.p)) {
         // allocate a page for the page table
         pde->in.p = 1;
         pde->in.rw = 1;
-        pde->in.us = (priv == 0);
+        pde->in.us = 1;
         pde->in.pt_page = alloc_raw_page();
 
-        make_page_table((page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page)));
+        memset(to_pt(pde), 0x00, PAGE_SIZE);
     }
 
     // map the page in the page table
-    page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
-    pte += linr_addr_to_pt_i(addr);
-    map_raw_page_to_pte(pte, page->phys_page_id, read, (write && !cow), priv);
+    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;
+        invalidate_tlb(addr);
+    }
+    ++*pg->ref_count;
 
-    mm_area->pgs->push_back(*page);
-    mm_area->pgs->back()->attr.cow = cow;
-    ++*page->ref_count;
+    auto iter = this->pgs->emplace_back(*pg);
+    iter->pte = pte;
     return GB_OK;
 }
 
-bool check_addr_range_avail(const mm* mm_area, void* start, void* end)
-{
-    void* m_start = (void*)mm_area->start;
-    void* m_end = (void*)(mm_area->start + PAGE_SIZE * mm_area->pgs->size());
-
-    if (start >= m_end || end <= m_start)
-        return true;
-    else
-        return false;
-}
-
 static inline int _mmap(
     mm_list* mms,
     void* hint,
@@ -481,7 +446,7 @@ static inline int _mmap(
     int write,
     int priv)
 {
-    if (!file->flags.in.file && !file->flags.in.special_node) {
+    if (unlikely(!file->flags.in.file && !file->flags.in.special_node)) {
         errno = EINVAL;
         return GB_FAILED;
     }
@@ -490,17 +455,17 @@ static inline int _mmap(
     size_t n_pgs = len >> 12;
 
     for (const auto& mm_area : *mms)
-        if (!check_addr_range_avail(&mm_area, hint, (char*)hint + len)) {
+        if (!mm_area.is_avail(hint, (char*)hint + len)) {
             errno = EEXIST;
             return GB_FAILED;
         }
 
-    auto iter_mm = mms->emplace_back((linr_ptr_t)hint, mms_get_pd(&current_process->mms), write, priv);
-    iter_mm->mapped_file = file;
-    iter_mm->file_offset = offset;
+    auto mm = mms->addarea(hint, write, priv);
+    mm->mapped_file = file;
+    mm->file_offset = offset;
 
     for (size_t i = 0; i < n_pgs; ++i)
-        k_map(iter_mm.ptr(), &empty_page, 0, write, priv, 1);
+        mm->append_page(&empty_page, false, write, priv, true);
 
     return GB_OK;
 }
@@ -522,9 +487,9 @@ int mmap(
 // to avoid dead loops
 static inline void _init_map_page_identically(page_t page)
 {
-    page_directory_entry* pde = KERNEL_PAGE_DIRECTORY_ADDR + page_to_pd_i(page);
+    pde_t* pde = *KERNEL_PAGE_DIRECTORY_ADDR + to_pdi(page);
     // page table not exist
-    if (!pde->in.p) {
+    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;
@@ -532,29 +497,25 @@ static inline void _init_map_page_identically(page_t page)
         pde->in.us = 0;
         pde->in.pt_page = alloc_raw_page();
         _init_map_page_identically(pde->in.pt_page);
-
-        make_page_table((page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page)));
+        memset(to_pt(pde), 0x00, PAGE_SIZE);
     }
 
     // map the page in the page table
-    page_table_entry* pt = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
-    pt += page_to_pt_i(page);
+    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 (phys_ptr_t addr = 0x01000000; addr < 0x30000000; addr += 0x1000) {
+    for (pptr_t addr = 0x01000000; addr < 0x30000000; addr += 0x1000) {
         // check if the address is valid and not mapped
-        if (bm_test(mem_bitmap, phys_addr_to_page(addr)))
+        if (bm_test(mem_bitmap, to_page(addr)))
             continue;
-        _init_map_page_identically(phys_addr_to_page(addr));
+        _init_map_page_identically(to_page(addr));
     }
 }
 
-page empty_page;
-
 void init_mem(void)
 {
     init_mem_layout();
@@ -562,34 +523,23 @@ void init_mem(void)
     // map the 16MiB-768MiB identically
     init_paging_map_low_mem_identically();
 
-    kernel_mms = types::kernel_ident_allocator_new<mm_list>();
-    auto heap_mm = kernel_mms->emplace_back((linr_ptr_t)KERNEL_HEAP_START, KERNEL_PAGE_DIRECTORY_ADDR, 1, 1);
-
-    page heap_first_page {
-        .phys_page_id = alloc_raw_page(),
-        .ref_count = types::kernel_ident_allocator_new<size_t>(0),
-        .attr = {
-            .cow = 0,
-        },
-    };
-
-    k_map(heap_mm.ptr(), &heap_first_page, 1, 1, 1, 0);
-    memset(KERNEL_HEAP_START, 0x00, PAGE_SIZE);
-    kernel_heap_allocator = types::kernel_ident_allocator_new<brk_memory_allocator>(KERNEL_HEAP_START,
-        (uint32_t)KERNEL_HEAP_LIMIT - (uint32_t)KERNEL_HEAP_START);
+    kernel_mms = types::kernel_ident_allocator_pnew(kernel_mms, KERNEL_PAGE_DIRECTORY_ADDR);
+    auto heap_mm = kernel_mms->addarea(KERNEL_HEAP_START, true, true);
 
     // create empty_page struct
-    empty_page.attr.cow = 0;
-    empty_page.phys_page_id = phys_addr_to_page(EMPTY_PAGE_ADDR);
+    empty_page.attr.in.cow = 0;
+    empty_page.phys_page_id = to_page(EMPTY_PAGE_ADDR);
     empty_page.ref_count = types::kernel_ident_allocator_new<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);
 
-    // TODO: improve the algorithm SO FREAKING SLOW
-    // while (kernel_mm_head->len < 256 * 1024 * 1024 / PAGE_SIZE) {
-    while (heap_mm->pgs->size() < 256 * 1024 * 1024 / PAGE_SIZE) {
-        k_map(
-            heap_mm.ptr(), &empty_page,
-            1, 1, 1, 1);
-    }
+    // 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::kernel_ident_allocator_pnew(kernel_heap_allocator,
+        KERNEL_HEAP_START, vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
 }
 
 void create_segment_descriptor(
@@ -607,31 +557,3 @@ void create_segment_descriptor(
     sd->access = access;
     sd->flags = flags;
 }
-
-mm::mm(linr_ptr_t start, page_directory_entry* pd, bool write, bool system)
-    : start(start)
-    , attr({
-          .read { 1 },
-          .write { write },
-          .system { system },
-      })
-    , pd(pd)
-    , pgs(types::kernel_ident_allocator_new<page_arr>())
-    , mapped_file(nullptr)
-    , file_offset(0)
-{
-}
-
-mm::mm(const mm& val)
-    : start(val.start)
-    , attr({
-          .read { val.attr.read },
-          .write { val.attr.write },
-          .system { val.attr.system },
-      })
-    , pd(val.pd)
-    , pgs(val.pgs)
-    , mapped_file(nullptr)
-    , file_offset(0)
-{
-}

+ 210 - 186
src/kernel/process.cpp

@@ -1,298 +1,322 @@
 #include <asm/port_io.h>
 #include <asm/sys.h>
+#include <fs/fat.hpp>
+#include <kernel/hw/ata.hpp>
+#include <kernel/interrupt.h>
+#include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
 #include <kernel/stdio.h>
 #include <kernel/tty.h>
-#include <kernel/hw/ata.hpp>
+#include <kernel/vfs.hpp>
 #include <kernel_main.h>
+#include <types/allocator.hpp>
+#include <types/assert.h>
+#include <types/elf.hpp>
+#include <types/hash_map.hpp>
+#include <types/list.hpp>
+#include <types/lock.hpp>
+#include <types/size.h>
+#include <types/status.h>
+#include <types/stdint.h>
 #include <types/types.h>
-#include <types/lock.h>
-#include <hello-world.res>
-#include <interrupt-test.res>
-
-extern "C" void NORETURN go_user_space(void* eip);
-extern "C" void NORETURN to_kernel(interrupt_stack* ret_stack);
-extern "C" void NORETURN to_user(interrupt_stack* ret_stack);
 
 static bool is_scheduler_ready;
 static types::list<process>* processes;
+static typename types::hash_map<pid_t, types::list<process>::iterator_type, types::linux_hasher<pid_t>>* idx_processes;
 static types::list<thread*>* ready_thds;
-static pid_t max_pid = 1;
-static void (* volatile kthreadd_new_thd_func)(void*);
-static void  * volatile kthreadd_new_thd_data;
-static uint32_t volatile kthreadd_lock = 0;
+static void (*volatile kthreadd_new_thd_func)(void*);
+static void* volatile kthreadd_new_thd_data;
+static types::mutex kthreadd_mtx;
+
+namespace kernel {
+
+struct no_irq_guard {
+    explicit no_irq_guard()
+    {
+        asm_cli();
+    }
+
+    no_irq_guard(const no_irq_guard&) = delete;
+    no_irq_guard& operator=(const no_irq_guard&) = delete;
+
+    ~no_irq_guard()
+    {
+        asm_sti();
+    }
+};
 
-thread* current_thread;
-process* current_process;
+} // namespace kernel
 
 process::process(process&& val)
     : mms(types::move(val.mms))
     , thds(types::move(val.thds))
+    , wait_lst(types::move(val.wait_lst))
     , pid(val.pid)
+    , ppid(val.ppid)
 {
     if (current_process == &val)
         current_process = this;
 
     attr.system = val.attr.system;
-    k_esp = val.k_esp;
 
     for (auto& item : thds)
         item.owner = this;
 
-    val.k_esp = nullptr;
     val.attr.system = 0;
 }
 
 process::process(const process& val, const thread& main_thd)
     : mms(*kernel_mms)
     , attr { .system = val.attr.system }
-    , pid { max_pid++ }
+    , pid { process::alloc_pid() }
+    , ppid { val.pid }
 {
     auto iter_thd = thds.emplace_back(main_thd);
     iter_thd->owner = this;
 
-    if (!val.attr.system) {
-        // TODO: allocate low mem
-        k_esp = (void*)page_to_phys_addr(alloc_n_raw_pages(2));
-        memset((char*)k_esp, 0x00, THREAD_KERNEL_STACK_SIZE);
-        k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
-
-        page_directory_entry* pd = alloc_pd();
-        memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
-
-        mms.begin()->pd = pd;
-        // skip kernel heap
-        for (auto iter_src = ++val.mms.cbegin(); iter_src != val.mms.cend(); ++iter_src) {
-            auto iter_dst = mms.emplace_back(iter_src->start, pd, iter_src->attr.write, iter_src->attr.system);
-            iter_dst->pd = pd;
-            for (auto pg = iter_src->pgs->begin(); pg != iter_src->pgs->end(); ++pg)
-                k_map(iter_dst.ptr(),
-                        &*pg,
-                        iter_src->attr.read,
-                        iter_src->attr.write,
-                        iter_src->attr.system,
-                        1);
-        }
-    } else {
-        // TODO: allocate low mem
-        k_esp = (void*)page_to_phys_addr(alloc_n_raw_pages(2));
-        memcpy(k_esp, main_thd.owner->k_esp, THREAD_KERNEL_STACK_SIZE);
-        k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
-
-        auto orig_k_esp = (uint32_t)main_thd.owner->k_esp;
+    for (auto& area : val.mms) {
+        if (area.is_ident())
+            continue;
 
-        iter_thd->regs.ebp -= orig_k_esp;
-        iter_thd->regs.ebp += (uint32_t)k_esp;
-
-        iter_thd->regs.esp -= orig_k_esp;
-        iter_thd->regs.esp += (uint32_t)k_esp;
+        mms.mirror_area(area);
     }
 }
 
-process::process(void* start_eip, uint8_t* image, size_t image_size, bool system)
+process::process(void)
     : mms(*kernel_mms)
-    , thds {}
-    , attr { .system = system }
-    , pid { max_pid++ }
+    , attr { .system = 1 }
+    , pid { process::alloc_pid() }
+    , ppid { 1 }
 {
-    // TODO: allocate low mem
-    k_esp = (void*)page_to_phys_addr(alloc_n_raw_pages(2));
-    memset((char*)k_esp, 0x00, THREAD_KERNEL_STACK_SIZE);
-    k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
-
-    auto thd = thds.emplace_back(thread {
-        .eip = start_eip,
-        .owner = this,
-        // TODO: change this
-        .regs {
-            .edi {},
-            .esi {},
-            .ebp = system ? (uint32_t)k_esp : 0x40100000U,
-            .esp = system ? (uint32_t)k_esp : 0x40100000U,
-            .ebx {},
-            .edx {},
-            .ecx {},
-            .eax {},
-        },
-        .eflags {},
-        .attr {
-            .system = system,
-            .ready = 1,
-            .wait = 0,
-        },
-    });
-    ready_thds->push_back(thd.ptr());
-
-    if (!system) {
-        page_directory_entry* pd = alloc_pd();
-        memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
-        for (auto& item : mms)
-            item.pd = pd;
-
-        auto user_mm = mms.emplace_back(0x40000000U, pd, 1, system);
-
-        // TODO: change this
-        for (int i = 0; i < 1 * 1024 * 1024 / PAGE_SIZE; ++i)
-            k_map(user_mm.ptr(), &empty_page, 1, 1, 0, 1);
-
-        auto* old_pd = reinterpret_cast<page_directory_entry*>(p_ptr_to_v_ptr(current_pd()));
-        auto* old_proc = current_process;
-        auto* old_thd = current_thread;
+    auto thd = thds.emplace_back(this, true);
 
-        current_process = this;
-        current_thread = thd.ptr();
-        asm_switch_pd(pd);
+    add_to_ready_list(thd.ptr());
+}
 
-        // TODO: change this
-        memcpy((void*)0x40000000U, image, image_size);
+process::process(void (*func)(void), pid_t _ppid)
+    : mms(*kernel_mms)
+    , attr { .system = 1 }
+    , pid { process::alloc_pid() }
+    , ppid { _ppid }
+{
+    auto thd = thds.emplace_back(this, true);
+
+    add_to_ready_list(thd.ptr());
+
+    auto* esp = &thd->esp;
+
+    // return(start) address
+    push_stack(esp, (uint32_t)func);
+    // ebx
+    push_stack(esp, 0);
+    // edi
+    push_stack(esp, 0);
+    // esi
+    push_stack(esp, 0);
+    // ebp
+    push_stack(esp, 0);
+    // eflags
+    push_stack(esp, 0x200);
+}
 
-        current_process = old_proc;
-        current_thread = old_thd;
-        asm_switch_pd(old_pd);
-    }
+process::~process()
+{
+    for (auto iter = thds.begin(); iter != thds.end(); ++iter)
+        remove_from_ready_list(iter.ptr());
+}
+
+inline void NORETURN _noreturn_crash(void)
+{
+    for (;;)
+        assert(false);
 }
 
+extern "C" void NORETURN go_kernel(uint32_t* kstack, void (*k_main)(void));
+extern "C" void NORETURN go_user(void* eip, uint32_t* esp);
+
 void kernel_threadd_main(void)
 {
     tty_print(console, "kernel thread daemon started\n");
-    k_new_thread(hw::init_ata, nullptr);
+
     for (;;) {
         if (kthreadd_new_thd_func) {
-            spin_lock(&kthreadd_lock);
-            int return_value = 0;
+            void (*func)(void*) = nullptr;
+            void* data = nullptr;
+
+            {
+                types::lock_guard lck(kthreadd_mtx);
+                func = kthreadd_new_thd_func;
+                data = kthreadd_new_thd_data;
 
-            void (*func)(void*) = kthreadd_new_thd_func;
-            void* data = kthreadd_new_thd_data;
-            kthreadd_new_thd_func = nullptr;
-            kthreadd_new_thd_data = nullptr;
+                kthreadd_new_thd_func = nullptr;
+                kthreadd_new_thd_data = nullptr;
+            }
 
-            spin_unlock(&kthreadd_lock);
+            // TODO
+            (void)func, (void)data;
+            assert(false);
 
             // syscall_fork
-            asm volatile("movl $0x00, %%eax\nint $0x80\nmovl %%eax, %0": "=a" (return_value): :);
-
-            if (return_value != 0) {
-                // child
-                func(data);
-                for (;;) asm_hlt();
-                // TODO: syscall_exit()
-            }
-            spin_unlock(&kthreadd_lock);
+            // int ret = syscall(0x00);
+
+            // if (ret == 0) {
+            //     // child process
+            //     func(data);
+            //     // the function shouldn't return here
+            //     assert(false);
+            // }
         }
+        // TODO: sleep here to wait for new_kernel_thread event
         asm_hlt();
     }
 }
 
-void k_new_thread(void(*func)(void*), void* data)
+void NORETURN _kernel_init(void)
+{
+    {
+        kernel::no_irq_guard grd;
+
+        add_to_process_list(process { kernel_threadd_main, 1 });
+    }
+    hw::init_ata();
+
+    // TODO: parse kernel parameters
+    auto* _new_fs = fs::register_fs(types::kernel_allocator_new<fs::fat::fat32>(fs::vfs_open("/dev/hda1")->ind));
+    int ret = fs::fs_root->ind->fs->mount(fs::vfs_open("/mnt"), _new_fs);
+    assert_likely(ret == GB_OK);
+
+    current_process->attr.system = 0;
+    current_thread->attr.system = 0;
+
+    const char* argv[] = { "/mnt/INIT.ELF", nullptr };
+
+    types::elf::elf32_load_data d;
+    d.exec = "/mnt/INIT.ELF";
+    d.argv = argv;
+    d.system = false;
+
+    assert(types::elf::elf32_load(&d) == GB_OK);
+
+    is_scheduler_ready = true;
+
+    go_user(d.eip, d.sp);
+}
+
+void k_new_thread(void (*func)(void*), void* data)
 {
-    spin_lock(&kthreadd_lock);
+    types::lock_guard lck(kthreadd_mtx);
     kthreadd_new_thd_func = func;
     kthreadd_new_thd_data = data;
-    spin_unlock(&kthreadd_lock);
 }
 
 void NORETURN init_scheduler()
 {
-    processes = types::kernel_allocator_new<types::list<process>>();
-    ready_thds = types::kernel_allocator_new<types::list<thread*>>();
-
-    void* user_space_start = reinterpret_cast<void*>(0x40000000U);
+    processes = types::kernel_allocator_pnew(processes);
+    ready_thds = types::kernel_allocator_pnew(ready_thds);
+    idx_processes = types::kernel_allocator_pnew(idx_processes);
+    idx_child_processes = types::kernel_allocator_pnew(idx_child_processes);
 
-    processes->emplace_back(user_space_start, hello_world_bin, hello_world_bin_len, false);
-    processes->emplace_back(user_space_start, interrupt_test_bin, interrupt_test_bin_len, false);
-    processes->emplace_back((void*)kernel_threadd_main, nullptr, 0, true);
+    auto pid = add_to_process_list(process {});
+    auto init = findproc(pid);
 
-    // we need interrupts enabled for cow mapping
+    // we need interrupts enabled for cow mapping so now we disable it
+    // in case timer interrupt mess things up
     asm_cli();
 
-    auto init_process = processes->begin();
-    current_process = init_process.ptr();
-    current_thread = init_process->thds.begin().ptr();
+    current_process = init;
+    current_thread = init->thds.begin().ptr();
+
     tss.ss0 = KERNEL_DATA_SEGMENT;
-    tss.esp0 = (uint32_t)init_process->k_esp;
-    asm_switch_pd(mms_get_pd(&current_process->mms));
+    tss.esp0 = current_thread->kstack;
 
-    is_scheduler_ready = true;
-    go_user_space(user_space_start);
-}
+    asm_switch_pd(current_process->mms.m_pd);
 
-void thread_context_save(interrupt_stack* int_stack, thread* thd)
-{
-    thd->eflags = int_stack->eflags;
-    thd->eip = int_stack->v_eip;
-    memcpy(&thd->regs, &int_stack->s_regs, sizeof(regs_32));
-    if (thd->attr.system)
-        thd->regs.esp = int_stack->s_regs.esp + 0x0c;
-    else
-        thd->regs.esp = int_stack->esp;
+    go_kernel(current_thread->esp, _kernel_init);
 }
 
-void thread_context_load(interrupt_stack* int_stack, thread* thd)
+pid_t add_to_process_list(process&& proc)
 {
-    int_stack->eflags = (thd->eflags | 0x200); // OR $STI
-    int_stack->v_eip = thd->eip;
-    memcpy(&int_stack->s_regs, &thd->regs, sizeof(regs_32));
-    current_thread = thd;
+    auto iter = processes->emplace_back(types::move(proc));
+    idx_processes->insert(iter->pid, iter);
+
+    auto children = idx_child_processes->find(iter->ppid);
+    if (!children) {
+        idx_child_processes->insert(iter->ppid, {});
+        children = idx_child_processes->find(iter->ppid);
+    }
+
+    children->value.push_back(iter->pid);
+
+    return iter->pid;
 }
 
-void process_context_save(interrupt_stack*, process*)
+void remove_from_process_list(pid_t pid)
 {
+    auto proc_iter = idx_processes->find(pid);
+    auto ppid = proc_iter->value->ppid;
+
+    auto& parent_children = idx_child_processes->find(ppid)->value;
+
+    auto i = parent_children.find(pid);
+    parent_children.erase(i);
+
+    processes->erase(proc_iter->value);
+    idx_processes->remove(proc_iter);
 }
 
-void process_context_load(interrupt_stack*, process* proc)
+void add_to_ready_list(thread* thd)
 {
-    if (!proc->attr.system)
-        tss.esp0 = (uint32_t)proc->k_esp;
-    asm_switch_pd(mms_get_pd(&proc->mms));
-    current_process = proc;
+    ready_thds->push_back(thd);
 }
 
-void add_to_process_list(process&& proc)
+void remove_from_ready_list(thread* thd)
 {
-    processes->push_back(types::move(proc));
+    auto iter = ready_thds->find(thd);
+    while (iter != ready_thds->end()) {
+        ready_thds->erase(iter);
+        iter = ready_thds->find(thd);
+    }
 }
 
-void add_to_ready_list(thread* thd)
+types::list<thread*>::iterator_type query_next_thread(void)
 {
-    ready_thds->push_back(thd);
+    auto iter_thd = ready_thds->begin();
+    while (!((*iter_thd)->attr.ready))
+        iter_thd = ready_thds->erase(iter_thd);
+    return iter_thd;
 }
 
-static inline void next_task(const types::list<thread*>::iterator_type& iter_to_remove, thread* cur_thd)
+process* findproc(pid_t pid)
 {
-    ready_thds->erase(iter_to_remove);
-    if (cur_thd->attr.ready)
-        ready_thds->push_back(cur_thd);
+    return idx_processes->find(pid)->value.ptr();
 }
 
-void do_scheduling(interrupt_stack* intrpt_data)
+extern "C" void asm_ctx_switch(uint32_t** curr_esp, uint32_t* next_esp);
+void schedule()
 {
-    if (!is_scheduler_ready)
+    if (unlikely(!is_scheduler_ready))
         return;
 
-    auto iter_thd = ready_thds->begin();
-    while (!((*iter_thd)->attr.ready))
-        iter_thd = ready_thds->erase(iter_thd);
+    auto iter_thd = query_next_thread();
     auto thd = *iter_thd;
 
     if (current_thread == thd) {
-        next_task(iter_thd, thd);
+        next_task(iter_thd);
         return;
     }
 
     process* proc = thd->owner;
     if (current_process != proc) {
-        process_context_save(intrpt_data, current_process);
-        process_context_load(intrpt_data, proc);
+        asm_switch_pd(proc->mms.m_pd);
+        current_process = proc;
     }
 
-    thread_context_save(intrpt_data, current_thread);
-    thread_context_load(intrpt_data, thd);
+    auto* curr_thd = current_thread;
 
-    next_task(iter_thd, thd);
+    current_thread = thd;
+    tss.esp0 = current_thread->kstack;
+    next_task(iter_thd);
 
-    if (thd->attr.system)
-        to_kernel(intrpt_data);
-    else
-        to_user(intrpt_data);
+    asm_ctx_switch(&curr_thd->esp, thd->esp);
 }

+ 177 - 22
src/kernel/syscall.cpp

@@ -1,41 +1,84 @@
 #include <asm/port_io.h>
-#include <kernel/syscall.hpp>
+#include <asm/sys.h>
+#include <kernel/errno.h>
+#include <kernel/interrupt.h>
+#include <kernel/mem.h>
+#include <kernel/mm.hpp>
 #include <kernel/process.hpp>
+#include <kernel/syscall.hpp>
 #include <kernel/tty.h>
+#include <kernel_main.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))
+
+#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)
 
 syscall_handler syscall_handlers[8];
 
 void _syscall_not_impl(interrupt_stack* data)
 {
-    data->s_regs.eax = 0xffffffff;
-    data->s_regs.edx = 0xffffffff;
+    SYSCALL_SET_RETURN_VAL(0xffffffff, 0xffffffff);
 }
 
+extern "C" void _syscall_stub_fork_return(void);
 void _syscall_fork(interrupt_stack* data)
 {
-    thread_context_save(data, current_thread);
-    process_context_save(data, current_process);
+    auto newpid = add_to_process_list(process { *current_process, *current_thread });
+    auto* newproc = findproc(newpid);
+    thread* newthd = newproc->thds.begin().ptr();
+    add_to_ready_list(newthd);
 
-    process new_proc(*current_process, *current_thread);
-    thread* new_thd = new_proc.thds.begin().ptr();
+    // create fake interrupt stack
+    push_stack(&newthd->esp, data->ss);
+    push_stack(&newthd->esp, data->esp);
+    push_stack(&newthd->esp, data->eflags);
+    push_stack(&newthd->esp, data->cs);
+    push_stack(&newthd->esp, (uint32_t)data->v_eip);
 
-    // return value
-    new_thd->regs.eax = 0;
-    data->s_regs.eax = new_proc.pid;
+    // eax
+    push_stack(&newthd->esp, 0);
+    push_stack(&newthd->esp, data->s_regs.ecx);
+    // edx
+    push_stack(&newthd->esp, 0);
+    push_stack(&newthd->esp, data->s_regs.ebx);
+    push_stack(&newthd->esp, data->s_regs.esp);
+    push_stack(&newthd->esp, data->s_regs.ebp);
+    push_stack(&newthd->esp, data->s_regs.esi);
+    push_stack(&newthd->esp, data->s_regs.edi);
 
-    new_thd->regs.edx = 0;
-    data->s_regs.edx = 0;
+    // ctx_switch stack
+    // return address
+    push_stack(&newthd->esp, (uint32_t)_syscall_stub_fork_return);
+    // ebx
+    push_stack(&newthd->esp, 0);
+    // edi
+    push_stack(&newthd->esp, 0);
+    // esi
+    push_stack(&newthd->esp, 0);
+    // ebp
+    push_stack(&newthd->esp, 0);
+    // eflags
+    push_stack(&newthd->esp, 0);
 
-    add_to_process_list(types::move(new_proc));
-    add_to_ready_list(new_thd);
+    SYSCALL_SET_RETURN_VAL(newpid, 0);
 }
 
 void _syscall_write(interrupt_stack* data)
 {
     tty_print(console, reinterpret_cast<const char*>(data->s_regs.edi));
 
-    data->s_regs.eax = 0;
-    data->s_regs.edx = 0;
+    SYSCALL_SET_RETURN_VAL(0, 0);
 }
 
 void _syscall_sleep(interrupt_stack* data)
@@ -43,10 +86,9 @@ void _syscall_sleep(interrupt_stack* data)
     current_thread->attr.ready = 0;
     current_thread->attr.wait = 1;
 
-    data->s_regs.eax = 0;
-    data->s_regs.edx = 0;
+    SYSCALL_SET_RETURN_VAL(0, 0);
 
-    do_scheduling(data);
+    schedule();
 }
 
 void _syscall_crash(interrupt_stack*)
@@ -56,14 +98,127 @@ void _syscall_crash(interrupt_stack*)
     asm_hlt();
 }
 
+// syscall_exec(const char* exec, const char** argv)
+// @param exec: the path of program to execute
+// @param argv: arguments 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();
+
+    types::elf::elf32_load_data d;
+    d.argv = argv;
+    d.exec = exec;
+    d.system = false;
+
+    assert(types::elf::elf32_load(&d) == GB_OK);
+
+    data->v_eip = d.eip;
+    data->esp = (uint32_t)d.sp;
+}
+
+// @param exit_code
+void _syscall_exit(interrupt_stack* data)
+{
+    uint32_t exit_code = data->s_regs.edi;
+    pid_t pid = current_process->pid;
+    pid_t ppid = current_process->ppid;
+
+    // TODO: terminating a thread only
+    if (current_thread->owner->thds.size() != 1) {
+        _syscall_crash(data);
+    }
+
+    // terminating a whole process:
+
+    // remove this thread from ready list
+    current_thread->attr.ready = 0;
+    remove_from_ready_list(current_thread);
+
+    // TODO: write back mmap'ped files and close them
+
+    // unmap all user memory areas
+    current_process->mms.clear_user();
+
+    // make child processes orphans (children of init)
+    auto children = idx_child_processes->find(pid);
+    if (children) {
+        auto init_children = idx_child_processes->find(1);
+        for (auto iter = children->value.begin(); iter != children->value.end(); ++iter) {
+            init_children->value.push_back(*iter);
+            findproc(*iter)->ppid = 1;
+        }
+        idx_child_processes->remove(children);
+    }
+
+    current_process->attr.zombie = 1;
+
+    // notify parent process and init
+    auto* proc = findproc(pid);
+    auto* parent = findproc(ppid);
+    auto* init = findproc(1);
+    while (!proc->wait_lst.empty()) {
+        init->wait_lst.push(proc->wait_lst.front());
+    }
+    parent->wait_lst.push({ current_thread, (void*)pid, (void*)exit_code, nullptr });
+
+    // switch to new process and continue
+    schedule();
+
+    // we should not return to here
+    assert(false);
+}
+
+// @param address of exit code: int*
+// @return pid of the exited process
+void _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() && !idx_child_processes->find(current_process->pid)) {
+        SYSCALL_SET_RETURN_VAL(-1, ECHILD);
+        return;
+    }
+
+    while (waitlst.empty()) {
+        current_thread->attr.ready = 0;
+        current_thread->attr.wait = 1;
+        waitlst.subscribe(current_thread);
+
+        schedule();
+
+        if (!waitlst.empty()) {
+            waitlst.unsubscribe(current_thread);
+            break;
+        }
+    }
+
+    auto evt = waitlst.front();
+
+    pid_t pid = (pid_t)evt.data1;
+    // TODO: copy_to_user check privilege
+    *arg1 = (int)evt.data2;
+
+    remove_from_process_list(pid);
+    SYSCALL_SET_RETURN_VAL(pid, 0);
+}
+
 void init_syscall(void)
 {
     syscall_handlers[0] = _syscall_fork;
     syscall_handlers[1] = _syscall_write;
     syscall_handlers[2] = _syscall_sleep;
     syscall_handlers[3] = _syscall_crash;
-    syscall_handlers[4] = _syscall_not_impl;
-    syscall_handlers[5] = _syscall_not_impl;
-    syscall_handlers[6] = _syscall_not_impl;
+    syscall_handlers[4] = _syscall_exec;
+    syscall_handlers[5] = _syscall_exit;
+    syscall_handlers[6] = _syscall_wait;
     syscall_handlers[7] = _syscall_not_impl;
 }

+ 14 - 9
src/kernel/vfs.cpp

@@ -1,10 +1,10 @@
 #include <kernel/errno.h>
 #include <kernel/mem.h>
 #include <kernel/stdio.h>
-#include <kernel/syscall.hpp>
 #include <kernel/tty.h>
 #include <kernel/vfs.hpp>
 #include <types/allocator.hpp>
+#include <types/assert.h>
 #include <types/list.hpp>
 #include <types/status.h>
 #include <types/stdint.h>
@@ -116,7 +116,7 @@ void fs::vfs::register_root_node(inode* root)
 }
 int fs::vfs::load_dentry(dentry*)
 {
-    syscall(0x03);
+    assert(false);
     return GB_FAILED;
 }
 int fs::vfs::mount(dentry* mnt, vfs* new_fs)
@@ -137,37 +137,37 @@ int fs::vfs::mount(dentry* mnt, vfs* new_fs)
 }
 size_t fs::vfs::inode_read(inode*, char*, size_t, size_t, size_t)
 {
-    syscall(0x03);
+    assert(false);
     return 0xffffffff;
 }
 size_t fs::vfs::inode_write(inode*, const char*, size_t, size_t)
 {
-    syscall(0x03);
+    assert(false);
     return 0xffffffff;
 }
 int fs::vfs::inode_mkfile(dentry*, const char*)
 {
-    syscall(0x03);
+    assert(false);
     return GB_FAILED;
 }
 int fs::vfs::inode_mknode(dentry*, const char*, node_t)
 {
-    syscall(0x03);
+    assert(false);
     return GB_FAILED;
 }
 int fs::vfs::inode_rmfile(dentry*, const char*)
 {
-    syscall(0x03);
+    assert(false);
     return GB_FAILED;
 }
 int fs::vfs::inode_mkdir(dentry*, const char*)
 {
-    syscall(0x03);
+    assert(false);
     return GB_FAILED;
 }
 int fs::vfs::inode_stat(dentry*, stat*)
 {
-    syscall(0x03);
+    assert(false);
     return GB_FAILED;
 }
 
@@ -384,6 +384,10 @@ fs::vfs::dentry* fs::vfs_open(const char* path)
             }
             if (path[n] == '/') {
                 cur = cur->find(string(path, n));
+
+                if (!cur)
+                    return cur;
+
                 if (path[n + 1] == 0x00) {
                     return cur;
                 } else {
@@ -466,6 +470,7 @@ void init_vfs(void)
 
     vfs_mkdir(fs_root, "dev");
     vfs_mkdir(fs_root, "root");
+    vfs_mkdir(fs_root, "mnt");
     vfs_mkfile(fs_root, "init");
 
     auto* init = vfs_open("/init");

+ 31 - 31
src/kernel_main.c

@@ -9,12 +9,14 @@
 #include <kernel/hw/timer.h>
 #include <kernel/interrupt.h>
 #include <kernel/mem.h>
-#include <kernel/process.hpp>
 #include <kernel/stdio.h>
 #include <kernel/task.h>
 #include <kernel/tty.h>
 #include <kernel/vga.h>
+#include <types/assert.h>
 #include <types/bitmap.h>
+#include <types/status.h>
+#include <types/types.h>
 
 #define KERNEL_MAIN_BUF_SIZE (128)
 
@@ -28,26 +30,6 @@ struct tty* console = NULL;
 #define INIT_OK() printkf("ok\n")
 #define INIT_FAILED() printkf("failed\n")
 
-static inline void check_a20_status(void)
-{
-    uint32_t result;
-    result = check_a20_on();
-
-    if (result) {
-        tty_print(console, "a20 is on");
-    } else {
-        tty_print(console, "a20 is NOT on");
-    }
-}
-
-static inline void halt_on_init_error(void)
-{
-    MAKE_BREAK_POINT();
-    asm_cli();
-    while (1)
-        asm_hlt();
-}
-
 typedef void (*constructor)(void);
 extern constructor start_ctors;
 extern constructor end_ctors;
@@ -128,7 +110,7 @@ void load_new_gdt(void)
     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, (phys_ptr_t)new_gdt);
+    asm_load_gdt((6 * 8 - 1) << 16, (pptr_t)new_gdt);
     asm_load_tr((6 - 1) * 8);
 
     asm_cli();
@@ -144,10 +126,12 @@ void init_bss_section(void)
 static struct tty early_console;
 
 extern void init_vfs();
+extern void NORETURN init_scheduler();
 
 void NORETURN kernel_main(void)
 {
-    // MAKE_BREAK_POINT();
+    assert(check_a20_on());
+
     asm_enable_sse();
 
     init_bss_section();
@@ -156,13 +140,10 @@ void NORETURN kernel_main(void)
 
     load_new_gdt();
 
-    char buf[KERNEL_MAIN_BUF_SIZE];
-
-    init_serial_port(PORT_SERIAL0);
+    char buf[KERNEL_MAIN_BUF_SIZE] = { 0 };
 
-    if (make_serial_tty(&early_console, PORT_SERIAL0) != GB_OK) {
-        halt_on_init_error();
-    }
+    assert(init_serial_port(PORT_SERIAL0) == GB_OK);
+    assert(make_serial_tty(&early_console, PORT_SERIAL0) == GB_OK);
     console = &early_console;
 
     show_mem_info(buf);
@@ -193,10 +174,29 @@ void NORETURN kernel_main(void)
     tty_print(console, k_malloc_buf);
     k_free(k_malloc_buf);
 
-    k_malloc_buf[4096] = '\x89';
-
     init_vfs();
 
     printkf("switching execution to the scheduler...\n");
     init_scheduler(&tss);
 }
+
+void NORETURN __stack_chk_fail(void)
+{
+    tty_print(console, "***** stack smashing detected! *****\n");
+    for (;;)
+        assert(0);
+}
+
+void crash(void)
+{
+    asm volatile("ud2");
+}
+
+void _debugger_breakpoint(void)
+{
+#ifdef __BOCHS_SYSTEM__
+    asm volatile("xchgw %%bx, %%bx");
+#else
+    asm volatile("nop");
+#endif
+}

+ 5 - 1
src/mbr.S

@@ -16,7 +16,11 @@ mbr_start:
 # read the first 64k
     call read_data
 
-# read the rest
+# read the following 128k
+    addw $(0x100 * 16), read_data_segment
+    addl $(8 * 16), read_data_lba
+    call read_data
+
     addw $(0x100 * 16), read_data_segment
     addl $(8 * 16), read_data_lba
     call read_data

+ 90 - 0
src/types/elf.cpp

@@ -0,0 +1,90 @@
+#include <kernel/errno.h>
+#include <kernel/stdio.h>
+#include <types/assert.h>
+#include <types/elf.hpp>
+#include <types/stdint.h>
+
+template <typename T>
+constexpr void _user_push(uint32_t** sp, T d)
+{
+    *sp -= sizeof(T);
+    *(T*)*sp = d;
+}
+
+int types::elf::elf32_load(types::elf::elf32_load_data* d)
+{
+    auto* ent_exec = fs::vfs_open(d->exec);
+    if (!ent_exec) {
+        d->errcode = ENOENT;
+        return GB_FAILED;
+    }
+
+    // TODO: detect file format
+    types::elf::elf32_header hdr {};
+    auto n_read = fs::vfs_read(
+        ent_exec->ind,
+        (char*)&hdr,
+        sizeof(types::elf::elf32_header),
+        0, sizeof(types::elf::elf32_header));
+
+    if (n_read != sizeof(types::elf::elf32_header)) {
+        d->errcode = EINVAL;
+        return GB_FAILED;
+    }
+
+    size_t phents_size = hdr.phentsize * hdr.phnum;
+    auto* phents = (types::elf::elf32_program_header_entry*)k_malloc(phents_size);
+    n_read = fs::vfs_read(
+        ent_exec->ind,
+        (char*)phents,
+        phents_size,
+        hdr.phoff, phents_size);
+
+    // broken file or I/O error
+    if (n_read != phents_size) {
+        d->errcode = EINVAL;
+        return GB_FAILED;
+    }
+
+    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) {
+            d->errcode = ret;
+            return GB_FAILED;
+        }
+
+        ++phents;
+    }
+
+    // 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);
+    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;
+
+    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);
+    }
+
+    *sp -= sizeof(const char*) * arr.size();
+    *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
+    memcpy((char*)*sp, arr.data(), sizeof(const char*) * arr.size());
+
+    _user_push(sp, 0);
+    _user_push(sp, 0);
+    _user_push(sp, *sp + 8);
+    _user_push(sp, arr.size());
+
+    return GB_OK;
+}

+ 20 - 13
user-space-program/Makefile.src

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

+ 62 - 0
user-space-program/basic-lib.h

@@ -0,0 +1,62 @@
+typedef __UINT32_TYPE__ uint32_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT8_TYPE__ uint8_t;
+
+typedef uint32_t pid_t;
+
+#define GNU_ATTRIBUTE(attr) __attribute__((attr))
+#define NORETURN GNU_ATTRIBUTE(noreturn)
+
+static inline uint32_t syscall(uint32_t num, 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"(num)
+        : "g"(arg1), "g"(arg2), "g"(num)
+        : "eax", "edx", "edi", "esi");
+    return num;
+}
+
+static inline void NORETURN syscall_noreturn(uint32_t num, 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"(num)
+        : "g"(arg1), "g"(arg2), "g"(num)
+        : "eax", "edx", "edi", "esi");
+    // crash
+    syscall_noreturn(0x05, 0, 0);
+}
+
+static inline int fork(void)
+{
+    return syscall(0x00, 0, 0);
+}
+static inline uint32_t write(const char* buf)
+{
+    return syscall(0x01, (uint32_t)buf, 0);
+}
+static inline void sleep(void)
+{
+    syscall(0x02, 0, 0);
+}
+static inline void NORETURN exec(const char* bin, const char** argv)
+{
+    syscall_noreturn(0x04, (uint32_t)bin, (uint32_t)argv);
+}
+static inline void NORETURN exit(int exit_code)
+{
+    syscall_noreturn(0x05, exit_code, 0);
+}
+static inline uint32_t wait(int* return_value)
+{
+    return syscall(0x06, (uint32_t)return_value, 0);
+}

+ 9 - 0
user-space-program/configure

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+cp Makefile.src Makefile
+
+make --always-make --dry-run \
+    | grep -wE 'gcc|g\+\+' \
+    | grep -w '\-c' \
+    | jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$").string[1:]}]' \
+    > compile_commands.json

+ 4 - 3
user-space-program/hello-world.s

@@ -1,8 +1,9 @@
 .code32
-.section .text.user-space
 
-.globl user_hello_world
-user_hello_world:
+.text
+
+.globl main
+main:
 	movl $0xcbcbcbcb, %eax
 	movl $0xacacacac, %ebx
 	jmp .

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

@@ -0,0 +1,25 @@
+#include "basic-lib.h"
+
+int main(int argc, char** argv)
+{
+    for (int i = 0; i < argc; ++i)
+        write(argv[i]);
+
+    const char* data = "Hello World from user space init\n";
+    write(data);
+    int ret = fork();
+    if (ret == 0) {
+        write("child\n");
+        exit(255);
+    } else {
+        write("parent\n");
+    }
+
+    for (;;) {
+        int ret;
+        pid_t pid = wait(&ret);
+        (void)pid;
+        pid += 1000;
+    }
+    return 0;
+}

+ 7 - 4
user-space-program/interrupt-test.s

@@ -1,8 +1,9 @@
 .code32
-.section .text.user-space
 
-.globl user_interrupt_test
-user_interrupt_test:
+.text
+
+.globl main
+main:
 # fork 1 -> 2
 	xorl %eax, %eax
 	int $0x80
@@ -22,5 +23,7 @@ user_interrupt_test:
 # noreturn
 	jmp .
 
+.data
+
 __user_interrupt_test_string:
-	.ascii "syscall 0x01 write: hello from user space\n\0"
+	.asciz "syscall 0x01 write: hello from user space\n"

+ 0 - 20
user-space-program/output_code.ld

@@ -1,20 +0,0 @@
-OUTPUT_FORMAT(binary)
-OUTPUT_ARCH(i386:i386)
-
-SECTIONS
-{
-    .text 0x40000000 : AT(0x00)
-    {
-        *(.text*)
-        *(.rodata*)
-        *(.data)
-        *(.data*)
-        *(.bss)
-        *(.bss*)
-    }
-
-    /DISCARD/ :
-    {
-        *(.note.gnu.property)
-    }
-}

+ 0 - 47
user-space-program/output_symbols.ld

@@ -1,47 +0,0 @@
-OUTPUT_FORMAT(elf32-i386)
-OUTPUT_ARCH(i386:i386)
-
-SECTIONS
-{
-    /DISCARD/ :
-    {
-        *(.text*)
-        *(.data)
-        *(.data*)
-        *(.note.gnu.property)
-    }
-
-    /* Stabs debugging sections.  */
-    .stab          0 : { *(.stab) }
-    .stabstr       0 : { *(.stabstr) }
-    .stab.excl     0 : { *(.stab.excl) }
-    .stab.exclstr  0 : { *(.stab.exclstr) }
-    .stab.index    0 : { *(.stab.index) }
-    .stab.indexstr 0 : { *(.stab.indexstr) }
-    .comment       0 : { *(.comment) }
-    /* DWARF debug sections.
-       Symbols in the DWARF debugging sections are relative to the beginning
-       of the section so we begin them at 0.  */
-    /* DWARF 1 */
-    .debug          0 : { *(.debug) }
-    .line           0 : { *(.line) }
-    /* GNU DWARF 1 extensions */
-    .debug_srcinfo  0 : { *(.debug_srcinfo) }
-    .debug_sfnames  0 : { *(.debug_sfnames) }
-    /* DWARF 1.1 and DWARF 2 */
-    .debug_aranges  0 : { *(.debug_aranges) }
-    .debug_pubnames 0 : { *(.debug_pubnames) }
-    /* DWARF 2 */
-    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
-    .debug_abbrev   0 : { *(.debug_abbrev) }
-    .debug_line     0 : { *(.debug_line) }
-    .debug_frame    0 : { *(.debug_frame) }
-    .debug_str      0 : { *(.debug_str) }
-    .debug_loc      0 : { *(.debug_loc) }
-    .debug_macinfo  0 : { *(.debug_macinfo) }
-    /* SGI/MIPS DWARF 2 extensions */
-    .debug_weaknames 0 : { *(.debug_weaknames) }
-    .debug_funcnames 0 : { *(.debug_funcnames) }
-    .debug_typenames 0 : { *(.debug_typenames) }
-    .debug_varnames  0 : { *(.debug_varnames) }
-}

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

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

+ 16 - 0
user-space-program/stack-test.s

@@ -0,0 +1,16 @@
+.code32
+
+.text
+
+.globl main
+.type  main @function
+main:
+	pushl %ebp
+	movl %esp, %ebp
+
+	movl %esp, %eax
+
+	movl %ebp, %esp
+	popl %ebp
+
+	jmp .