Explorar o código

Merge branch 'vfs-refactor'

greatbridf hai 2 meses
pai
achega
f4128f04a0
Modificáronse 100 ficheiros con 4186 adicións e 3149 borrados
  1. 7 0
      .cargo/config.toml
  2. 23 132
      .clang-format
  3. 8 0
      .gitignore
  4. 79 0
      .rustfmt.toml
  5. 67 46
      CMakeLists.txt
  6. 329 0
      Cargo.lock
  7. 32 0
      Cargo.toml
  8. 3 2
      Makefile.src
  9. 28 0
      build.rs
  10. 5 10
      configure
  11. 0 15
      cross-compile.cmake
  12. 29 8
      doc/mem_layout.txt
  13. 34 2
      gblibc/CMakeLists.txt
  14. 2 2
      gblibc/include/alloca.h
  15. 0 1
      gblibc/include/bits/alltypes.h
  16. 2 0
      gblibc/include/bits/ioctl.h
  17. 6 0
      gblibc/include/errno.h
  18. 7 0
      gblibc/include/fcntl.h
  19. 35 0
      gblibc/include/poll.h
  20. 51 4
      gblibc/include/signal.h
  21. 1 1
      gblibc/include/stdint.h
  22. 21 0
      gblibc/include/sys/mount.h
  23. 8 6
      gblibc/include/sys/types.h
  24. 43 0
      gblibc/include/sys/utsname.h
  25. 12 0
      gblibc/include/sys/wait.h
  26. 182 0
      gblibc/include/termios.h
  27. 1 0
      gblibc/include/time.h
  28. 5 0
      gblibc/include/unistd.h
  29. 0 6
      gblibc/src/alloca.c
  30. 10 1
      gblibc/src/errno.c
  31. 15 1
      gblibc/src/fcntl.c
  32. 29 4
      gblibc/src/init.c
  33. 24 6
      gblibc/src/stdlib.c
  34. 17 41
      gblibc/src/string.c
  35. 32 1
      gblibstdc++/CMakeLists.txt
  36. 70 0
      gblibstdc++/include/bits/compressed_pair
  37. 84 71
      gblibstdc++/include/bits/rbtree
  38. 5 8
      gblibstdc++/include/functional
  39. 43 50
      gblibstdc++/include/list
  40. 11 12
      gblibstdc++/include/map
  41. 506 383
      gblibstdc++/include/memory
  42. 1 1
      gblibstdc++/include/queue
  43. 4 4
      gblibstdc++/include/set
  44. 543 0
      gblibstdc++/include/string
  45. 9 9
      gblibstdc++/include/tuple
  46. 1 1
      gblibstdc++/include/utility
  47. 72 71
      gblibstdc++/include/vector
  48. 1 1
      global_find.sh
  49. 0 36
      include/asm/port_io.h
  50. 0 27
      include/asm/sys.h
  51. 20 0
      include/defs.hpp
  52. 0 175
      include/fs/fat.hpp
  53. 66 0
      include/kernel/async/lock.hpp
  54. 29 0
      include/kernel/async/waitlist.hpp
  55. 0 16
      include/kernel/event/event.h
  56. 0 38
      include/kernel/event/evtqueue.hpp
  57. 35 0
      include/kernel/hw/acpi.hpp
  58. 0 15
      include/kernel/hw/keyboard.h
  59. 47 57
      include/kernel/hw/pci.hpp
  60. 15 33
      include/kernel/hw/port.hpp
  61. 0 1
      include/kernel/hw/serial.hpp
  62. 0 17
      include/kernel/hw/timer.h
  63. 11 0
      include/kernel/hw/timer.hpp
  64. 27 25
      include/kernel/input/keycodes.h
  65. 0 57
      include/kernel/interrupt.h
  66. 43 0
      include/kernel/interrupt.hpp
  67. 1 1
      include/kernel/irq.hpp
  68. 19 4
      include/kernel/log.hpp
  69. 0 141
      include/kernel/mem.h
  70. 112 0
      include/kernel/mem/mm_list.hpp
  71. 175 0
      include/kernel/mem/paging.hpp
  72. 27 0
      include/kernel/mem/paging_asm.h
  73. 53 0
      include/kernel/mem/phys.hpp
  74. 37 0
      include/kernel/mem/slab.hpp
  75. 36 0
      include/kernel/mem/types.hpp
  76. 60 0
      include/kernel/mem/vm_area.hpp
  77. 0 405
      include/kernel/mm.hpp
  78. 23 20
      include/kernel/module.hpp
  79. 76 343
      include/kernel/process.hpp
  80. 47 58
      include/kernel/signal.hpp
  81. 113 4
      include/kernel/syscall.hpp
  82. 0 18
      include/kernel/task.h
  83. 5 0
      include/kernel/task/current.hpp
  84. 7 0
      include/kernel/task/forward.hpp
  85. 16 0
      include/kernel/task/readyqueue.hpp
  86. 76 0
      include/kernel/task/thread.hpp
  87. 44 31
      include/kernel/tty.hpp
  88. 1 1
      include/kernel/user/thread_local.hpp
  89. 9 0
      include/kernel/utsname.hpp
  90. 62 313
      include/kernel/vfs.hpp
  91. 28 0
      include/kernel/vfs/dentry.hpp
  92. 106 0
      include/kernel/vfs/file.hpp
  93. 51 0
      include/kernel/vfs/filearr.hpp
  94. 25 0
      include/kernel/vfs/vfsfwd.hpp
  95. 22 0
      include/net/arp.hpp
  96. 22 0
      include/net/ethernet.hpp
  97. 42 0
      include/net/netdev.hpp
  98. 30 315
      include/types/allocator.hpp
  99. 21 27
      include/types/bitmap.hpp
  100. 50 71
      include/types/buffer.hpp

+ 7 - 0
.cargo/config.toml

@@ -0,0 +1,7 @@
+[build]
+target = 'x86_64-unknown-none.json'
+target-dir = 'build'
+
+[unstable]
+build-std-features = ['compiler-builtins-mem']
+build-std = ['core', 'compiler_builtins', 'alloc']

+ 23 - 132
.clang-format

@@ -1,137 +1,28 @@
 ---
-Language:        Cpp
-# BasedOnStyle:  WebKit
-AccessModifierOffset: -4
-AlignAfterOpenBracket: DontAlign
-AlignConsecutiveMacros: false
-AlignConsecutiveAssignments: false
-AlignConsecutiveDeclarations: false
-AlignEscapedNewlines: Right
-AlignOperands:   false
-AlignTrailingComments: false
-AllowAllArgumentsOnNextLine: true
-AllowAllConstructorInitializersOnNextLine: true
-AllowAllParametersOfDeclarationOnNextLine: true
-AllowShortBlocksOnASingleLine: Empty
-AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: All
-AllowShortLambdasOnASingleLine: All
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: 'false'
+AllowShortCaseLabelsOnASingleLine: 'false'
+AllowShortFunctionsOnASingleLine: Inline
 AllowShortIfStatementsOnASingleLine: Never
-AllowShortLoopsOnASingleLine: false
-AlwaysBreakAfterDefinitionReturnType: None
-AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: false
-AlwaysBreakTemplateDeclarations: MultiLine
-BinPackArguments: true
-BinPackParameters: true
-BraceWrapping:
-  AfterCaseLabel:  false
-  AfterClass:      false
-  AfterControlStatement: false
-  AfterEnum:       false
-  AfterFunction:   true
-  AfterNamespace:  false
-  AfterObjCDeclaration: false
-  AfterStruct:     false
-  AfterUnion:      false
-  AfterExternBlock: false
-  BeforeCatch:     false
-  BeforeElse:      false
-  IndentBraces:    false
-  SplitEmptyFunction: true
-  SplitEmptyRecord: true
-  SplitEmptyNamespace: true
-BreakBeforeBinaryOperators: All
-BreakBeforeBraces: WebKit
-BreakBeforeInheritanceComma: false
-BreakInheritanceList: BeforeColon
-BreakBeforeTernaryOperators: true
-BreakConstructorInitializersBeforeComma: false
+AllowShortLoopsOnASingleLine: 'false'
 BreakConstructorInitializers: BeforeComma
-BreakAfterJavaFieldAnnotations: false
-BreakStringLiterals: true
-ColumnLimit:     0
-CommentPragmas:  '^ IWYU pragma:'
-CompactNamespaces: false
-ConstructorInitializerAllOnOneLineOrOnePerLine: false
-ConstructorInitializerIndentWidth: 4
-ContinuationIndentWidth: 4
-Cpp11BracedListStyle: false
-DeriveLineEnding: true
-DerivePointerAlignment: false
-DisableFormat:   false
-ExperimentalAutoDetectBinPacking: false
-FixNamespaceComments: false
-ForEachMacros:
-  - foreach
-  - Q_FOREACH
-  - BOOST_FOREACH
-IncludeBlocks:   Preserve
-IncludeCategories:
-  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
-    Priority:        2
-    SortPriority:    0
-  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
-    Priority:        3
-    SortPriority:    0
-  - Regex:           '.*'
-    Priority:        1
-    SortPriority:    0
-IncludeIsMainRegex: '(Test)?$'
-IncludeIsMainSourceRegex: ''
-IndentCaseLabels: false
-IndentGotoLabels: true
-IndentPPDirectives: None
-IndentWidth:     4
-IndentWrappedFunctionNames: false
-JavaScriptQuotes: Leave
-JavaScriptWrapImports: true
-KeepEmptyLinesAtTheStartOfBlocks: true
-MacroBlockBegin: ''
-MacroBlockEnd:   ''
-MaxEmptyLinesToKeep: 1
+FixNamespaceComments: 'true'
+IncludeBlocks: Regroup
+IndentWidth: '4'
 NamespaceIndentation: Inner
-ObjCBinPackProtocolList: Auto
-ObjCBlockIndentWidth: 4
-ObjCSpaceAfterProperty: true
-ObjCSpaceBeforeProtocolList: true
-PenaltyBreakAssignment: 2
-PenaltyBreakBeforeFirstCallParameter: 19
-PenaltyBreakComment: 300
-PenaltyBreakFirstLessLess: 120
-PenaltyBreakString: 1000
-PenaltyBreakTemplateDeclaration: 10
-PenaltyExcessCharacter: 1000000
-PenaltyReturnTypeOnItsOwnLine: 60
-PointerAlignment: Left
-ReflowComments:  true
-SortIncludes:    true
-SortUsingDeclarations: true
-SpaceAfterCStyleCast: false
-SpaceAfterLogicalNot: false
-SpaceAfterTemplateKeyword: true
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeCpp11BracedList: true
-SpaceBeforeCtorInitializerColon: true
-SpaceBeforeInheritanceColon: true
-SpaceBeforeParens: ControlStatements
-SpaceBeforeRangeBasedForLoopColon: true
-SpaceInEmptyBlock: true
-SpaceInEmptyParentheses: false
-SpacesBeforeTrailingComments: 1
-SpacesInAngles:  false
-SpacesInConditionalStatement: false
-SpacesInContainerLiterals: true
-SpacesInCStyleCastParentheses: false
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-SpaceBeforeSquareBrackets: false
-Standard:        Latest
-StatementMacros:
-  - Q_UNUSED
-  - QT_REQUIRE_VERSION
-TabWidth:        8
-UseCRLF:         false
-UseTab:          Never
-...
+SpacesBeforeTrailingComments: '1'
+Language: Cpp
+Standard: Cpp11
+IncludeCategories:
+  - Regex: '^<types/'
+    Priority: '4'
+  - Regex: '^<(kernel|fs|net|driver)/'
+    Priority: '5'
+  - Regex: '^<.*\.h>'
+    Priority: '3'
+  - Regex: '^<.*>'
+    Priority: '2'
+  - Regex: '.*'
+    Priority: '1'
 
+...

+ 8 - 0
.gitignore

@@ -13,3 +13,11 @@ compile_commands.json
 
 Makefile
 cross-compile.cmake
+
+.DS_Store
+.Spotlight-V100
+.Trashes
+
+.gdbinit
+
+src/bindings.rs

+ 79 - 0
.rustfmt.toml

@@ -0,0 +1,79 @@
+max_width = 80
+hard_tabs = false
+tab_spaces = 4
+newline_style = "Auto"
+indent_style = "Block"
+use_small_heuristics = "Default"
+fn_call_width = 60
+attr_fn_like_width = 70
+struct_lit_width = 18
+struct_variant_width = 35
+array_width = 60
+chain_width = 60
+single_line_if_else_max_width = 50
+single_line_let_else_max_width = 50
+wrap_comments = false
+format_code_in_doc_comments = false
+doc_comment_code_block_width = 100
+comment_width = 80
+normalize_comments = false
+normalize_doc_attributes = false
+format_strings = false
+format_macro_matchers = false
+format_macro_bodies = true
+skip_macro_invocations = []
+hex_literal_case = "Preserve"
+empty_item_single_line = true
+struct_lit_single_line = true
+fn_single_line = false
+where_single_line = false
+imports_indent = "Block"
+imports_layout = "Mixed"
+imports_granularity = "Preserve"
+group_imports = "Preserve"
+reorder_imports = true
+reorder_modules = true
+reorder_impl_items = false
+type_punctuation_density = "Wide"
+space_before_colon = false
+space_after_colon = true
+spaces_around_ranges = false
+binop_separator = "Front"
+remove_nested_parens = true
+combine_control_expr = true
+short_array_element_width_threshold = 10
+overflow_delimited_expr = false
+struct_field_align_threshold = 0
+enum_discrim_align_threshold = 0
+match_arm_blocks = true
+match_arm_leading_pipes = "Never"
+force_multiline_blocks = false
+fn_params_layout = "Tall"
+brace_style = "SameLineWhere"
+control_brace_style = "AlwaysSameLine"
+trailing_semicolon = true
+trailing_comma = "Vertical"
+match_block_trailing_comma = false
+blank_lines_upper_bound = 1
+blank_lines_lower_bound = 0
+edition = "2015"
+version = "One"
+inline_attribute_width = 0
+format_generated_files = true
+generated_marker_line_search_limit = 5
+merge_derives = true
+use_try_shorthand = false
+use_field_init_shorthand = false
+force_explicit_abi = true
+condense_wildcard_suffixes = false
+color = "Auto"
+required_version = "1.7.1"
+unstable_features = false
+disable_all_formatting = false
+skip_children = false
+show_parse_errors = true
+error_on_line_overflow = false
+error_on_unformatted = false
+ignore = []
+emit_mode = "Files"
+make_backup = false

+ 67 - 46
CMakeLists.txt

@@ -6,19 +6,23 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 set(CMAKE_CXX_LINK_EXECUTABLE
     "<CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
-set(CMAKE_ASM_FLAGS "-m32")
-set(C_CXX_FLAGS "-nostdinc -m32 -nostdlib -W -Wall -Wextra -Wno-builtin-declaration-mismatch -Wno-format -fverbose-asm -fno-exceptions -ffreestanding -fno-pic -mstack-protector-guard=global")
+set(C_CXX_FLAGS "-nostdinc -nostdlib -W -Wall -Wextra -Wno-stringop-overflow -Wno-builtin-declaration-mismatch -Wno-format -fverbose-asm -fno-exceptions -ffreestanding -fno-pic -mno-red-zone -mstack-protector-guard=global -mcmodel=kernel")
 set(CMAKE_C_FLAGS "${C_CXX_FLAGS} -Werror=implicit-int -Werror=implicit-function-declaration -Werror=strict-aliasing")
 set(CMAKE_CXX_FLAGS "${C_CXX_FLAGS} -fno-use-cxa-atexit -fno-rtti")
-set(CMAKE_CXX_LINK_FLAGS "")
+set(CMAKE_CXX_LINK_FLAGS "-z noexecstack --gc-sections")
+SET(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
 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")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG -O0 -g")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG -O0 -g")
+    set(CARGO_BUILD_TYPE "debug")
+    set(CARGO_BUILD_FLAGS "")
 elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -g -DNDEBUG")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -g -DNDEBUG")
+    set(CARGO_BUILD_TYPE "release")
+    set(CARGO_BUILD_FLAGS "--release")
 endif()
 
 if (NOT DEFINED FDISK_BIN)
@@ -30,80 +34,101 @@ add_subdirectory(gblibstdc++)
 add_subdirectory(user-space-program)
 
 set(BOOTLOADER_SOURCES src/boot.s
+                       src/mbr.S
                        src/asm/interrupt.s
-                       src/asm/port_io.s
-                       src/asm/sys.s
                        )
 
-set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
+set(KERNEL_MAIN_SOURCES src/dev/builtin-chardev.cc
                         src/kinit.cpp
+                        src/kernel/async/waitlist.cc
+                        src/kernel/async/lock.cc
+                        src/kernel/allocator.cc
                         src/kernel/interrupt.cpp
                         src/kernel/process.cpp
                         src/kernel/tty.cpp
                         src/kernel/syscall.cpp
-                        src/kernel/mem.cpp
+                        src/kernel/syscall/fileops.cc
+                        src/kernel/syscall/infoops.cc
+                        src/kernel/syscall/mount.cc
+                        src/kernel/syscall/procops.cc
+                        src/kernel/mem/mm_list.cc
+                        src/kernel/mem/paging.cc
+                        src/kernel/mem/slab.cc
                         src/kernel/module.cc
                         src/kernel/vfs.cpp
                         src/kernel/vga.cpp
-                        src/kernel/hw/ahci.cc
-                        src/kernel/hw/keyboard.cpp
+                        src/kernel/hw/acpi.cc
                         src/kernel/hw/pci.cc
-                        src/kernel/hw/serial.cpp
-                        src/kernel/hw/timer.c
-                        src/kernel/event/event.cpp
+                        src/kernel/hw/serial.cc
+                        src/kernel/hw/timer.cc
+                        src/kernel/task/thread.cc
+                        src/kernel/task/readyqueue.cc
                         src/kernel/user/thread_local.cc
+                        src/kernel/vfs/filearr.cc
                         src/kernel/signal.cpp
+                        src/net/ethernet.cc
+                        src/types/crc.cc
                         src/types/elf.cpp
                         src/types/libstdcpp.cpp
-                        include/asm/port_io.h
-                        include/asm/sys.h
-                        include/fs/fat.hpp
-                        include/kernel/event/event.h
-                        include/kernel/event/evtqueue.hpp
+                        include/defs.hpp
+                        include/kernel/async/waitlist.hpp
+                        include/kernel/async/lock.hpp
                         include/kernel/tty.hpp
-                        include/kernel/interrupt.h
+                        include/kernel/interrupt.hpp
                         include/kernel/irq.hpp
                         include/kernel/process.hpp
                         include/kernel/syscall.hpp
-                        include/kernel/mem.h
-                        include/kernel/mm.hpp
+                        include/kernel/mem/mm_list.hpp
+                        include/kernel/mem/paging.hpp
+                        include/kernel/mem/slab.hpp
+                        include/kernel/mem/types.hpp
+                        include/kernel/mem/vm_area.hpp
                         include/kernel/module.hpp
+                        include/kernel/utsname.hpp
                         include/kernel/vfs.hpp
+                        include/kernel/vfs/dentry.hpp
+                        include/kernel/vfs/file.hpp
+                        include/kernel/vfs/filearr.hpp
                         include/kernel/vga.hpp
                         include/kernel/signal.hpp
-                        include/kernel/hw/keyboard.h
+                        include/kernel/task/forward.hpp
+                        include/kernel/task/thread.hpp
+                        include/kernel/task/readyqueue.hpp
+                        include/kernel/hw/acpi.hpp
                         include/kernel/hw/pci.hpp
                         include/kernel/hw/port.hpp
-                        include/kernel/hw/serial.h
-                        include/kernel/hw/timer.h
+                        include/kernel/hw/serial.hpp
+                        include/kernel/hw/timer.hpp
                         include/kernel/input/keycodes.h
-                        include/kernel/input/input_event.h
                         include/kernel/user/thread_local.hpp
+                        include/net/arp.hpp
+                        include/net/ethernet.hpp
+                        include/net/netdev.hpp
                         include/types/bitmap.hpp
                         include/types/buffer.hpp
                         include/types/elf.hpp
-                        include/types/hash_map.hpp
+                        include/types/list.hpp
                         include/types/types.h
-                        include/types/size.h
-                        include/types/status.h
                         include/types/allocator.hpp
                         include/types/cplusplus.hpp
-                        include/types/lock.hpp
-                        include/types/string.hpp
                         include/kernel/log.hpp
                         )
 
 add_executable(kernel.out ${KERNEL_MAIN_SOURCES} ${BOOTLOADER_SOURCES})
-target_link_libraries(kernel.out gblibc gblibstdc++)
+add_dependencies(kernel.out rustpart)
+target_link_libraries(kernel.out gblibc gblibstdc++ gbos_rust_part)
 target_include_directories(kernel.out PRIVATE ${PROJECT_SOURCE_DIR}/include)
 target_link_options(kernel.out PRIVATE
-    -T ${CMAKE_SOURCE_DIR}/src/kernel.ld -melf_i386 -lgblibc -L${CMAKE_BINARY_DIR}/gblibc)
-set_target_properties(kernel.out PROPERTIES LINK_DEPENDS ${CMAKE_SOURCE_DIR}/src/kernel.ld)
+    -T "${CMAKE_SOURCE_DIR}/src/kernel.ld"
+    -L "${CMAKE_BINARY_DIR}/x86_64-unknown-none/${CARGO_BUILD_TYPE}"
+    )
+set_target_properties(kernel.out PROPERTIES LINK_DEPENDS "${CMAKE_SOURCE_DIR}/src/kernel.ld")
+set_source_files_properties(src/mbr.S PROPERTIES OBJECT_DEPENDS
+    "${CMAKE_BINARY_DIR}/x86_64-unknown-none/${CARGO_BUILD_TYPE}/libgbos_rust_part.a"
+    )
 
-add_custom_command(OUTPUT mbr.bin
-    DEPENDS ${PROJECT_SOURCE_DIR}/src/mbr.S ${PROJECT_SOURCE_DIR}/src/mbr.ld
-    COMMAND ${CMAKE_ASM_COMPILER} -m32 -c ${PROJECT_SOURCE_DIR}/src/mbr.S -o mbr.o
-    COMMAND ${CMAKE_LINKER} -T ${PROJECT_SOURCE_DIR}/src/mbr.ld mbr.o -o mbr.bin
+add_custom_target(rustpart
+    COMMAND cargo build ${CARGO_BUILD_FLAGS}
 )
 
 add_custom_command(OUTPUT mbr_hole.bin
@@ -112,11 +137,9 @@ add_custom_command(OUTPUT 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=mbr_hole.bin of=boot.img
     COMMAND dd if=/dev/zero of=boot.img bs=`expr 512 \\* 1024 \\* 1024` count=0 seek=1
     COMMAND sh -c \"echo n\; echo\; echo\; echo\; echo\; echo a\; echo w\" | ${FDISK_BIN} boot.img
     COMMAND mkfs.fat --offset=2048 -v -n SYSTEM boot.img
@@ -124,12 +147,10 @@ add_custom_target(boot.img
     COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/interrupt-test.out ::int
     COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/stack-test.out ::stack
     COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/init.out ::init
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/sh.out ::sh
     COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/priv-test.out ::priv
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/lazybox.out ::lazybox
-    COMMAND mcopy -i boot.img@@1M ${CMAKE_BINARY_DIR}/user-space-program/lazybox.out ::pwd
     COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/busybox-minimal ::busybox_
     COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/busybox ::busybox
+    COMMAND mcopy -i boot.img@@1M ${CMAKE_SOURCE_DIR}/init_script.sh ::initsh
 )
 
 add_custom_command(OUTPUT run

+ 329 - 0
Cargo.lock

@@ -0,0 +1,329 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "bindgen"
+version = "0.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "gbos-rust-part"
+version = "0.1.0"
+dependencies = [
+ "bindgen",
+ "itertools",
+ "lazy_static",
+ "spin",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.159"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+
+[[package]]
+name = "libloading"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+dependencies = [
+ "cfg-if",
+ "windows-targets",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

+ 32 - 0
Cargo.toml

@@ -0,0 +1,32 @@
+[package]
+name = "gbos-rust-part"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+itertools = { version = "0.13.0", default-features = false }
+lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
+spin = "0.9.8"
+
+[build-dependencies]
+bindgen = "0.70.1"
+
+[profile.dev]
+panic = "abort"
+
+[profile.dev.package."*"]
+opt-level = 2
+debug = false
+
+[profile.dev.build-override]
+opt-level = 0
+codegen-units = 256
+debug = false
+
+[profile.release.build-override]
+opt-level = 0
+codegen-units = 256
+debug = false

+ 3 - 2
Makefile.src

@@ -6,7 +6,7 @@ QEMU_DEBUG_FLAG=#-d cpu_reset,int
 QEMU_ARGS=-machine q35 -drive id=disk,file=build/boot.img,format=raw,if=none \
 	-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 \
 	-no-reboot -no-shutdown $(QEMU_ACCELERATION_FLAG) $(QEMU_DEBUG_FLAG)
-	
+
 CROSS_COMPILE=##PLACEHOLDER_4##
 .PHONY: run
 run: build
@@ -42,7 +42,8 @@ clean-all: clean
 
 .PHONY: debug
 debug:
-	$(GDB_BIN) --symbols=build/kernel.out --init-eval-command 'set pagination off' --init-eval-command 'target remote:1234' --eval-command 'hbr kernel_main' --eval-command 'c'
+	-$(GDB_BIN) --symbols=build/kernel.out --init-eval-command 'source pretty-print.py' --init-eval-command 'set pagination off' --init-eval-command 'set output-radix 16' --init-eval-command 'set print pretty on' --init-eval-command 'target remote:1234'
+	-killall $(QEMU_BIN)
 
 build/boot.vdi: build/boot.img
 	-rm build/boot.vdi

+ 28 - 0
build.rs

@@ -0,0 +1,28 @@
+fn main() {
+    println!("cargo:rustc-link-search=native=./build/gblibstdc++");
+    println!("cargo:rustc-link-lib=static=gblibstdc++");
+
+    let headers = [
+        "include/kernel/process.hpp",
+        "include/kernel/hw/pci.hpp",
+    ];
+
+    let bindings = bindgen::Builder::default()
+        .use_core()
+        .ctypes_prefix("core::ffi")
+        .headers(headers)
+        .clang_arg("-I./gblibstdc++/include")
+        .clang_arg("-I./gblibc/include")
+        .clang_arg("-I./include")
+        .clang_arg("-std=c++20")
+        .opaque_type("std::.*")
+        .enable_cxx_namespaces()
+        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
+        .generate()
+        .expect("Unable to generate bindings");
+
+    let out_path = std::path::PathBuf::from(std::env::var("PWD").unwrap());
+    bindings
+        .write_to_file(out_path.join("src/bindings.rs"))
+        .expect("Couldn't write bindings!");
+}

+ 5 - 10
configure

@@ -1,5 +1,5 @@
 #!/bin/sh
-QEMU_EXECUTABLES="qemu-system-i386 qemu-system-x86_64"
+QEMU_EXECUTABLES="qemu-system-x86_64"
 GDB_EXECUTABLES="gdb x86_64-elf-gdb"
 
 event() {
@@ -77,18 +77,13 @@ case "$OS" in
         QEMU_ACCEL='-enable-kvm'
         ;;
     "Darwin")
-        if [ "$QEMU" = "qemu-system-x86_64" ]; then
-            echo "hvf"
-            QEMU_ACCEL='-accel hvf'
-        else
-            echo "tcg"
-            QEMU_ACCEL='-accel tcg'
-        fi
+        echo "tcg"
+        QEMU_ACCEL='-accel tcg'
         ;;
 esac
 
 event "checking util-linux fdisk"
-if [ "$CROSS_COMPILE" = "" -o "$FDISK_BIN" = "" ]; then
+if [ "$FDISK_BIN" = "" -a "$CROSS_COMPILE" = "" ]; then
     if ! which fdisk > /dev/null 2>&1; then
         echo "no"
         exit 1
@@ -97,7 +92,7 @@ if [ "$CROSS_COMPILE" = "" -o "$FDISK_BIN" = "" ]; then
 fi
 
 if ! $FDISK_BIN -v 2>&1 | grep util-linux > /dev/null 2>&1 ; then
-    echo "no"
+    echo "no, fdisk is not from util-linux"
     exit 1
 else
     echo "$FDISK_BIN"

+ 0 - 15
cross-compile.cmake

@@ -1,15 +0,0 @@
-set(CMAKE_SYSTEM_NAME Darwin)
-
-set(TOOLCHAIN_PATH_AND_PREFIX "/usr/local/bin/x86_64-elf-")
-
-set(CMAKE_C_COMPILER ${TOOLCHAIN_PATH_AND_PREFIX}gcc)
-set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PATH_AND_PREFIX}c++)
-set(CMAKE_AR ${TOOLCHAIN_PATH_AND_PREFIX}ar)
-set(CMAKE_LINKER ${TOOLCHAIN_PATH_AND_PREFIX}ld)
-set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
-
-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)

+ 29 - 8
doc/mem_layout.txt

@@ -1,12 +1,33 @@
-0x00000000 - 0x00001000 kernel pd
-0x00001000 - 0x00005000 kernel pt
-0x00005000 - 0x00006000 empty page
+physical memory
 
-....
+0x0000 - 0x1000 : GDT, TSS, LDT and some early kernel data
+0x1000 - 0x2000 : kernel stage1
+0x2000 - 0x3000 : kernel PML4
+0x3000 - 0x4000 : kernel PDPT for physical memory mappings
+0x4000 - 0x5000 : kernel PDPT for kernel space
+0x5000 - 0x6000 : kernel PD for kernel image
+0x6000 - 0x7000 : kernel PT for kernel image
+0x7000 - 0x8000 : kernel PD for struct page array#1
 
-0x00100000 - 0x???????? kernel code, data, bss
-0x???????? - 0x01000000 kernel early stack
+0x100000 - 0x200000 : unused
+0x200000 - 0x400000 : first kernel bss page (2MB)
+0x400000 - ?        : kernel image
+?        - ?        : struct page array
 
-....
 
-0x30000000 - 0x40000000 kernel heap
+virtual address space
+
+0xffff ff0 000 000 000 - 0xffff ff3 fff fff fff  256GB physical memory (cached)
+0xffff ff4 000 000 000 - 0xffff ff7 fff fff fff  256GB physical memory (not cached)
+0xffff ff8 000 000 000 - 0xffff ff8 03f fff fff    1GB unused
+0xffff ff8 040 000 000 - 0xffff ff8 13f fff fff    4GB struct page array
+0xffff ff8 140 000 000 - 0xffff ff8 17f fff fff    1GB unused
+0xffff ff8 180 000 000 - 0xffff ffb fff fff fff  250GB kernel heap
+
+0xffff ffc 000 000 000 - 0xffff fff fbf fff fff  255GB unused
+
+0xffff fff fc0 000 000 - 0xffff fff fc0 1ff fff    2MB unused
+0xffff fff fc0 200 000 - 0xffff fff fff 9ff fff 1016MB kernel bss
+0xffff fff fff a00 000 - 0xffff fff fff bff fff    2MB unused
+0xffff fff fff c00 000 - 0xffff fff fff dff fff    2MB kernel image
+0xffff fff fff e00 000 - 0xffff fff fff fff fff    2MB unused

+ 34 - 2
gblibc/CMakeLists.txt

@@ -15,17 +15,42 @@ add_library(gblibc STATIC
     src/errno.c
     src/init.c
     src/internal.c
-    src/alloca.c
     src/stat.c
     src/time.c
     src/signal.c
     src/platform-independent.s
 )
 
-add_library(crt0 OBJECT
+add_library(gblibc_32 STATIC
+    src/stdio.c
+    src/arithmetic.c
+    src/string.c
+    src/fcntl.c
+    src/unistd.c
+    src/wait.c
+    src/assert.c
+    src/dirent.c
+    src/ctype.c
+    src/stdlib.c
+    src/errno.c
+    src/init.c
+    src/internal.c
+    src/stat.c
+    src/time.c
+    src/signal.c
+    src/platform-independent.s
+)
+
+add_library(crt0_32 OBJECT
     src/crt0.s
 )
 
+target_compile_options(gblibc_32 PRIVATE "-m32")
+target_compile_options(gblibc_32 PRIVATE "-mcmodel=32")
+target_compile_options(crt0_32 PRIVATE "-m32")
+target_link_options(gblibc_32 PRIVATE "LINKER:-melf_i386")
+target_link_options(crt0_32 PRIVATE "LINKER:-melf_i386")
+
 file(GLOB_RECURSE GBLIBC_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include)
 
 target_include_directories(gblibc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -34,3 +59,10 @@ target_include_directories(gblibc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
 set_target_properties(gblibc PROPERTIES PRIVATE_HEADER
     "private-include/devutil.h,private-include/syscall.h")
 set_target_properties(gblibc PROPERTIES PUBLIC_HEADER "${GBLIBC_PUBLIC_HEADERS}")
+
+target_include_directories(gblibc_32 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
+                                  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/private-include)
+
+set_target_properties(gblibc_32 PROPERTIES PRIVATE_HEADER
+    "private-include/devutil.h,private-include/syscall.h")
+set_target_properties(gblibc_32 PROPERTIES PUBLIC_HEADER "${GBLIBC_PUBLIC_HEADERS}")

+ 2 - 2
gblibc/include/alloca.h

@@ -3,12 +3,12 @@
 
 #include <stdint.h>
 
+#define alloca(size) __builtin_alloca(size)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-void* alloca(size_t size);
-
 #ifdef __cplusplus
 }
 #endif

+ 0 - 1
gblibc/include/bits/alltypes.h

@@ -13,7 +13,6 @@ typedef size_t blkcnt_t;
 struct timespec {
     time_t tv_sec;
     long tv_nsec;
-    int : 32; // padding
 };
 
 struct timeval {

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

@@ -3,6 +3,8 @@
 
 #include <sys/uio.h>
 
+#define TCGETS (0x5401)
+#define TCSETS (0x5402)
 #define TIOCGPGRP (0x540f)
 #define TIOCSPGRP (0x5410)
 #define TIOCGWINSZ (0x5413)

+ 6 - 0
gblibc/include/errno.h

@@ -17,14 +17,20 @@ extern int* __errno_location(void);
 #define EIO 5
 #define EBADF 9
 #define ECHILD 10
+#define EAGAIN 11
 #define ENOMEM 12
 #define EACCES 13
+#define EFAULT 14
 #define EEXIST 17
+#define ENODEV 19
 #define ENOTDIR 20
 #define EISDIR 21
 #define EINVAL 22
 #define ENOTTY 25
+#define ESPIPE 29
+#define EROFS 30
 #define EPIPE 32
+#define ELOOP 40
 
 #ifdef __cplusplus
 }

+ 7 - 0
gblibc/include/fcntl.h

@@ -16,6 +16,9 @@
 #define F_DUPFD 0
 #define F_GETFD 1
 #define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+#define F_DUPFD_CLOEXEC 1030
 // TODO: more flags
 
 #define FD_CLOEXEC 1
@@ -29,6 +32,10 @@
 #define AT_STATX_SYNC_FORCE   0x8000
 #define AT_STATX_DONT_SYNC    0x2000
 
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 35 - 0
gblibc/include/poll.h

@@ -0,0 +1,35 @@
+#ifndef __GBLIBC_POLL_H_
+#define __GBLIBC_POLL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int nfds_t;
+
+#define POLLIN          0x0001          /* any readable data available */
+#define POLLPRI         0x0002          /* OOB/Urgent readable data */
+#define POLLOUT         0x0004          /* file descriptor is writeable */
+#define POLLRDNORM      0x0040          /* non-OOB/URG data available */
+#define POLLWRNORM      POLLOUT         /* no write type differentiation */
+#define POLLRDBAND      0x0080          /* OOB/Urgent readable data */
+#define POLLWRBAND      0x0100          /* OOB/Urgent data can be written */
+
+#define POLLERR         0x0008          /* some poll error occurred */
+#define POLLHUP         0x0010          /* file descriptor was "hung up" */
+#define POLLNVAL        0x0020          /* requested events "invalid" */
+
+#define POLLSTANDARD    (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|\
+	                 POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
+
+struct pollfd {
+	int     fd;
+	short   events;
+	short   revents;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 51 - 4
gblibc/include/signal.h

@@ -7,10 +7,57 @@
 extern "C" {
 #endif
 
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGPIPE 13
-#define SIGSTOP 19
+#define SIGHUP    1
+#define SIGINT    2
+#define SIGQUIT   3
+#define SIGILL    4
+#define SIGTRAP   5
+#define SIGABRT   6
+#define SIGIOT    SIGABRT
+#define SIGBUS    7
+#define SIGFPE    8
+#define SIGKILL   9
+#define SIGUSR1   10
+#define SIGSEGV   11
+#define SIGUSR2   12
+#define SIGPIPE   13
+#define SIGALRM   14
+#define SIGTERM   15
+#define SIGSTKFLT 16
+#define SIGCHLD   17
+#define SIGCONT   18
+#define SIGSTOP   19
+#define SIGTSTP   20
+#define SIGTTIN   21
+#define SIGTTOU   22
+#define SIGURG    23
+#define SIGXCPU   24
+#define SIGXFSZ   25
+#define SIGVTALRM 26
+#define SIGPROF   27
+#define SIGWINCH  28
+#define SIGIO     29
+#define SIGPOLL   29
+#define SIGPWR    30
+#define SIGSYS    31
+#define SIGUNUSED SIGSYS
+#define SIGRTMIN  32
+#define SIGRTMAX  64
+
+#define SIG_BLOCK 0
+#define SIG_UNBLOCK 1
+#define SIG_SETMASK 2
+
+#define SA_RESTORER 0x04000000
+#define SA_ONSTACK  0x08000000
+#define SA_RESTART  0x10000000
+#define SA_NODEFER  0x40000000
+
+#define SIG_DFL ((sighandler_t)0)
+#define SIG_IGN ((sighandler_t)1)
+
+typedef void (*sighandler_t)(int);
+typedef void (*sigrestorer_t)(void);
 
 int kill(pid_t pid, int sig);
 int raise(int sig);

+ 1 - 1
gblibc/include/stdint.h

@@ -22,7 +22,7 @@ typedef __UINTPTR_TYPE__ uintptr_t;
 typedef __INTPTR_TYPE__ intptr_t;
 
 typedef __SIZE_TYPE__ size_t;
-typedef int32_t ssize_t;
+typedef int64_t ssize_t;
 
 typedef uint64_t time_t;
 typedef int64_t time_diff_t;

+ 21 - 0
gblibc/include/sys/mount.h

@@ -0,0 +1,21 @@
+#ifndef __GBLIBC_SYS_MOUNT_H
+#define __GBLIBC_SYS_MOUNT_H
+
+#define MS_RDONLY      (1 <<  0)
+#define MS_NOSUID      (1 <<  1)
+#define MS_NODEV       (1 <<  2)
+#define MS_NOEXEC      (1 <<  3)
+#define MS_NOATIME     (1 << 10)
+#define MS_RELATIME    (1 << 21)
+#define MS_STRICTATIME (1 << 24)
+#define MS_LAZYTIME    (1 << 25)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 8 - 6
gblibc/include/sys/types.h

@@ -8,16 +8,18 @@ extern "C" {
 #endif
 
 typedef int pid_t;
-typedef uint32_t ino_t;
-typedef int32_t off_t;
-typedef uint32_t dev_t;
+typedef unsigned long ino_t;
+typedef long off_t;
+typedef unsigned dev_t;
 typedef unsigned uid_t;
 typedef unsigned gid_t;
-typedef unsigned mode_t;
+typedef unsigned short mode_t;
 typedef unsigned long nlink_t;
 
-typedef uint64_t ino64_t;
-typedef int64_t off64_t;
+typedef unsigned long long ino64_t;
+typedef long long off64_t;
+
+typedef off64_t loff_t;
 
 #ifdef __cplusplus
 }

+ 43 - 0
gblibc/include/sys/utsname.h

@@ -0,0 +1,43 @@
+#ifndef __GBLIBC_SYS_UTSNAME_H
+#define __GBLIBC_SYS_UTSNAME_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OLD_UTSNAME_LENGTH 8
+
+struct oldold_utsname {
+    char sysname[9];
+    char nodename[9];
+    char release[9];
+    char version[9];
+    char machine[9];
+};
+
+#define UTSNAME_LENGTH 64
+
+struct old_utsname {
+    char sysname[65];
+    char nodename[65];
+    char release[65];
+    char version[65];
+    char machine[65];
+};
+
+struct new_utsname {
+    char sysname[65];
+    char nodename[65];
+    char release[65];
+    char version[65];
+    char machine[65];
+    char domainname[65];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

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

@@ -3,6 +3,18 @@
 
 #include <sys/types.h>
 
+#define WNOHANG 1
+#define WUNTRACED 2
+
+#define WEXISTATUS(s) (((s) & 0xff00) >> 8)
+#define WTERMSIG(s) ((s) & 0x7f)
+#define WSTOPSIG(s) WEXITSTATUS(s)
+#define WCOREDUMP(s) ((s) & 0x80)
+#define WIFEXITED(s) (!WTERMSIG(s))
+#define WIFSTOPPED(s) (((s) & 0x7f) == 0x7f)
+#define WIFSIGNALED(s) (WTERMSIG(s) && !WIFSTOPPED(s))
+#define WIFCONTINUED(s) ((s) == 0xffff)
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 182 - 0
gblibc/include/termios.h

@@ -0,0 +1,182 @@
+#ifndef __GBLIBC_TERMIOS_H_
+#define __GBLIBC_TERMIOS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NCCS 32
+
+typedef unsigned char cc_t;
+typedef unsigned int speed_t;
+typedef unsigned int tcflag_t;
+
+struct termios {
+    tcflag_t c_iflag;
+    tcflag_t c_oflag;
+    tcflag_t c_cflag;
+    tcflag_t c_lflag;
+
+    cc_t c_line;
+    cc_t c_cc[NCCS];
+
+    speed_t c_ispeed;
+    speed_t c_ospeed;
+};
+
+// taken from linux kernel code
+
+/* c_cc characters */
+#define VINTR		 0
+#define VQUIT		 1
+#define VERASE		 2
+#define VKILL		 3
+#define VEOF		 4
+#define VTIME		 5
+#define VMIN		 6
+#define VSWTC		 7
+#define VSTART		 8
+#define VSTOP		 9
+#define VSUSP		10
+#define VEOL		11
+#define VREPRINT	12
+#define VDISCARD	13
+#define VWERASE		14
+#define VLNEXT		15
+#define VEOL2		16
+
+/* c_iflag bits */
+#define IGNBRK	0x0001			/* Ignore break condition */
+#define BRKINT	0x0002			/* Signal interrupt on break */
+#define IGNPAR	0x0004			/* Ignore characters with parity errors */
+#define PARMRK	0x0008			/* Mark parity and framing errors */
+#define INPCK	0x0010			/* Enable input parity check */
+#define ISTRIP	0x0020			/* Strip 8th bit off characters */
+#define INLCR	0x0040			/* Map NL to CR on input */
+#define IGNCR	0x0080			/* Ignore CR */
+#define ICRNL	0x0100			/* Map CR to NL on input */
+#define IUCLC	0x0200
+#define IXON	0x0400
+#define IXANY	0x0800			/* Any character will restart after stop */
+#define IXOFF	0x1000
+#define IMAXBEL	0x2000
+#define IUTF8	0x4000
+
+/* c_oflag bits */
+#define OPOST	0x00001			/* Perform output processing */
+#define OLCUC	0x00002
+#define ONLCR	0x00004
+#define OCRNL	0x00008
+#define ONOCR	0x00010
+#define ONLRET	0x00020
+#define OFILL	0x00040
+#define OFDEL	0x00080
+#define NLDLY	0x00100
+#define   NL0	0x00000
+#define   NL1	0x00100
+#define CRDLY	0x00600
+#define   CR0	0x00000
+#define   CR1	0x00200
+#define   CR2	0x00400
+#define   CR3	0x00600
+#define TABDLY	0x01800
+#define   TAB0	0x00000
+#define   TAB1	0x00800
+#define   TAB2	0x01000
+#define   TAB3	0x01800
+#define   XTABS	0x01800
+#define BSDLY	0x02000
+#define   BS0	0x00000
+#define   BS1	0x02000
+#define VTDLY	0x04000
+#define   VT0	0x00000
+#define   VT1	0x04000
+#define FFDLY	0x08000
+#define   FF0	0x00000
+#define   FF1	0x08000
+
+/* c_cflag bit meaning */
+/* Common CBAUD rates */
+#define     B0		0x00000000	/* hang up */
+#define    B50		0x00000001
+#define    B75		0x00000002
+#define   B110		0x00000003
+#define   B134		0x00000004
+#define   B150		0x00000005
+#define   B200		0x00000006
+#define   B300		0x00000007
+#define   B600		0x00000008
+#define  B1200		0x00000009
+#define  B1800		0x0000000a
+#define  B2400		0x0000000b
+#define  B4800		0x0000000c
+#define  B9600		0x0000000d
+#define B19200		0x0000000e
+#define B38400		0x0000000f
+#define EXTA		B19200
+#define EXTB		B38400
+
+#define ADDRB		0x20000000	/* address bit */
+#define CMSPAR		0x40000000	/* mark or space (stick) parity */
+#define CRTSCTS		0x80000000	/* flow control */
+
+#define IBSHIFT		16		/* Shift from CBAUD to CIBAUD */
+
+#define CBAUD		0x0000100f
+#define CSIZE		0x00000030
+#define   CS5		0x00000000
+#define   CS6		0x00000010
+#define   CS7		0x00000020
+#define   CS8		0x00000030
+#define CSTOPB		0x00000040
+#define CREAD		0x00000080
+#define PARENB		0x00000100
+#define PARODD		0x00000200
+#define HUPCL		0x00000400
+#define CLOCAL		0x00000800
+#define CBAUDEX		0x00001000
+#define BOTHER		0x00001000
+#define     B57600	0x00001001
+#define    B115200	0x00001002
+#define    B230400	0x00001003
+#define    B460800	0x00001004
+#define    B500000	0x00001005
+#define    B576000	0x00001006
+#define    B921600	0x00001007
+#define   B1000000	0x00001008
+#define   B1152000	0x00001009
+#define   B1500000	0x0000100a
+#define   B2000000	0x0000100b
+#define   B2500000	0x0000100c
+#define   B3000000	0x0000100d
+#define   B3500000	0x0000100e
+#define   B4000000	0x0000100f
+#define CIBAUD		0x100f0000	/* input baud rate */
+
+/* c_lflag bits */
+#define ISIG	0x00001
+#define ICANON	0x00002
+#define XCASE	0x00004
+#define ECHO	0x00008
+#define ECHOE	0x00010
+#define ECHOK	0x00020
+#define ECHONL	0x00040
+#define NOFLSH	0x00080
+#define TOSTOP	0x00100
+#define ECHOCTL	0x00200
+#define ECHOPRT	0x00400
+#define ECHOKE	0x00800
+#define FLUSHO	0x01000
+#define PENDIN	0x04000
+#define IEXTEN	0x08000
+#define EXTPROC	0x10000
+
+// line disciplines
+
+#define N_TTY 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 0
gblibc/include/time.h

@@ -9,6 +9,7 @@ extern "C" {
 #endif
 
 #define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 1
 typedef int clockid_t;
 
 #ifdef __cplusplus

+ 5 - 0
gblibc/include/unistd.h

@@ -10,6 +10,11 @@
 #define STDOUT_FILENO (1)
 #define STDERR_FILENO (2)
 
+#define F_OK 0
+#define R_OK 1
+#define W_OK 2
+#define X_OK 4
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 0 - 6
gblibc/src/alloca.c

@@ -1,6 +0,0 @@
-#include <alloca.h>
-
-void* alloca(size_t size)
-{
-    return __builtin_alloca(size);
-}

+ 10 - 1
gblibc/src/errno.c

@@ -8,6 +8,15 @@ int* __errno_location(void)
     return &__errno;
 }
 
+static size_t _strlen(const char* str)
+{
+    size_t len = 0;
+    while (str[len] != '\0') {
+        len++;
+    }
+    return len;
+}
+
 void
 __attribute__((noreturn))
 __attribute__((weak))
@@ -15,7 +24,7 @@ __stack_chk_fail(void)
 {
     const char* msg = "***** stack overflow detected *****\n"
                       "quiting...\n";
-    write(STDERR_FILENO, msg, strlen(msg));
+    write(STDERR_FILENO, msg, _strlen(msg));
     exit(-1);
 }
 

+ 15 - 1
gblibc/src/fcntl.c

@@ -1,10 +1,24 @@
+#include <stdarg.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <syscall.h>
 
+#include <sys/types.h>
+
 int open(const char* filename, int flags, ...)
 {
-    int ret = syscall2(SYS_open, (uint32_t)filename, flags);
+    int ret;
+    if (flags | O_CREAT) {
+        va_list vl;
+        va_start(vl, flags);
+
+        ret = syscall3(SYS_open, (uint32_t)filename, flags, va_arg(vl, int));
+
+        va_end(vl);
+    }
+    else
+        ret = syscall2(SYS_open, (uint32_t)filename, flags);
+
     if (ret < 0) {
         errno = -ret;
         return -1;

+ 29 - 4
gblibc/src/init.c

@@ -2,7 +2,6 @@
 #include <priv-vars.h>
 #include <stdlib.h>
 #include <syscall.h>
-#include <string.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <list.h>
@@ -11,6 +10,32 @@ FILE* stdout;
 FILE* stdin;
 FILE* stderr;
 
+#define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
+static void* _memset(void* _dst, int c, size_t n)
+{
+    uint8_t* dst = (uint8_t*)_dst;
+    c &= 0xff;
+    int cc = (c + (c << 8) + (c << 16) + (c << 24));
+    for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
+        *(uint32_t*)dst = cc;
+        dst += BYTES_PER_MAX_COPY_UNIT;
+    }
+    for (size_t i = 0; i < (n % BYTES_PER_MAX_COPY_UNIT); ++i) {
+        *((char*)dst++) = c;
+    }
+    return dst;
+}
+
+static char* strchr(const char* s, int c)
+{
+    while (*s) {
+        if (*s == c)
+            return (char*)s;
+        ++s;
+    }
+    return NULL;
+}
+
 list_head* __io_files_location(void)
 {
     static list_head __io_files;
@@ -58,7 +83,7 @@ void __init_gblibc(int argc, char** argv, char** envp)
     // stdout
     node = NEWNODE(FILE);
     stdout = &NDDATA(*node, FILE);
-    memset(stdout, 0x00, sizeof(FILE));
+    _memset(stdout, 0x00, sizeof(FILE));
 
     stdout->fd = STDOUT_FILENO;
     stdout->flags = FILE_WRITE;
@@ -70,7 +95,7 @@ void __init_gblibc(int argc, char** argv, char** envp)
     // stdin
     node = NEWNODE(FILE);
     stdin = &NDDATA(*node, FILE);
-    memset(stdin, 0x00, sizeof(FILE));
+    _memset(stdin, 0x00, sizeof(FILE));
 
     stdin->fd = STDIN_FILENO;
     stdin->flags = FILE_READ;
@@ -82,7 +107,7 @@ void __init_gblibc(int argc, char** argv, char** envp)
     // stderr
     node = NEWNODE(FILE);
     stderr = &NDDATA(*node, FILE);
-    memset(stderr, 0x00, sizeof(FILE));
+    _memset(stderr, 0x00, sizeof(FILE));
 
     stderr->fd = STDERR_FILENO;
     stderr->flags = FILE_WRITE;

+ 24 - 6
gblibc/src/stdlib.c

@@ -7,6 +7,24 @@
 #include <unistd.h>
 #include <string.h>
 
+#define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
+
+static void* _memcpy(void* _dst, const void* _src, size_t n)
+{
+    void* orig_dst = _dst;
+    uint8_t* dst = (uint8_t*)_dst;
+    const uint8_t* src = (const uint8_t*)_src;
+    for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
+        *(uint32_t*)dst = *(uint32_t*)src;
+        dst += BYTES_PER_MAX_COPY_UNIT;
+        src += BYTES_PER_MAX_COPY_UNIT;
+    }
+    for (size_t i = 0; i < (n % BYTES_PER_MAX_COPY_UNIT); ++i) {
+        *((char*)dst++) = *((char*)src++);
+    }
+    return orig_dst;
+}
+
 int atoi(const char* str)
 {
     int ret = 0;
@@ -155,7 +173,7 @@ void* realloc(void* ptr, size_t newsize)
     if (!newptr)
         return NULL;
     
-    memcpy(newptr, ptr, oldsize);
+    _memcpy(newptr, ptr, oldsize);
     free(ptr);
     return newptr;
 }
@@ -170,9 +188,9 @@ void free(void* ptr)
 static inline void _swap(void* a, void* b, size_t sz)
 {
     void* tmp = alloca(sz);
-    memcpy(tmp, a, sz);
-    memcpy(a, b, sz);
-    memcpy(b, tmp, sz);
+    _memcpy(tmp, a, sz);
+    _memcpy(a, b, sz);
+    _memcpy(b, tmp, sz);
 }
 
 void qsort(void* arr, size_t len, size_t sz, comparator_t cmp) {
@@ -180,7 +198,7 @@ void qsort(void* arr, size_t len, size_t sz, comparator_t cmp) {
         return;
 
     char* pivot = alloca(sz);
-    memcpy(pivot, arr + sz * (rand() % len), sz);
+    _memcpy(pivot, arr + sz * (rand() % len), sz);
 
     int i = 0, j = 0, k = len;
     while (i < k) {
@@ -252,7 +270,7 @@ int setenv(const char* name, const char* value, int overwrite)
         if (!newarr)
             return -1;
         
-        memcpy(newarr, environ, sizeof(char*) * environ_size / 2);
+        _memcpy(newarr, environ, sizeof(char*) * environ_size / 2);
         free(environ);
         environ = newarr;
     }

+ 17 - 41
gblibc/src/string.c

@@ -6,26 +6,7 @@
 
 #define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
 
-int memcmp(const void* ptr1, const void* ptr2, size_t num)
-{
-    while (num--) {
-        if (*(const char*)ptr1 < *(const char*)ptr2)
-            return -1;
-        else if (*(const char*)ptr1 > *(const char*)ptr2)
-            return 1;
-    }
-    return 0;
-}
-
-void* memmove(void* dst, const void* src, size_t n)
-{
-    void* orig_dst = dst;
-    while (n--)
-        *(char*)(dst++) = *(const char*)(src++);
-    return orig_dst;
-}
-
-void* memcpy(void* _dst, const void* _src, size_t n)
+static void* _memcpy(void* _dst, const void* _src, size_t n)
 {
     void* orig_dst = _dst;
     uint8_t* dst = (uint8_t*)_dst;
@@ -41,12 +22,7 @@ void* memcpy(void* _dst, const void* _src, size_t n)
     return orig_dst;
 }
 
-void* mempcpy(void* dst, const void* src, size_t n)
-{
-    return memcpy(dst, src, n) + n;
-}
-
-void* memset(void* _dst, int c, size_t n)
+static void* _memset(void* _dst, int c, size_t n)
 {
     uint8_t* dst = (uint8_t*)_dst;
     c &= 0xff;
@@ -61,7 +37,7 @@ void* memset(void* _dst, int c, size_t n)
     return dst;
 }
 
-size_t strlen(const char* str)
+static size_t _strlen(const char* str)
 {
     size_t n = 0;
     while (*(str++) != '\0')
@@ -82,7 +58,7 @@ char* strchr(const char* str, int c)
 
 char* strrchr(const char* str, int c)
 {
-    const char* p = str + strlen(str) - 1;
+    const char* p = str + _strlen(str) - 1;
     while (p >= str) {
         if (*p == c)
             return (char*)p;
@@ -96,23 +72,23 @@ char* strchrnul(const char* str, int c)
     char* ret = strchr(str, c);
     if (ret)
         return ret;
-    return (char*)str + strlen(str);
+    return (char*)str + _strlen(str);
 }
 
 char* strcpy(char* dst, const char* src)
 {
-    return memcpy(dst, src, strlen(src) + 1);
+    return _memcpy(dst, src, _strlen(src) + 1);
 }
 
 char* strncpy(char* dst, const char* src, size_t n)
 {
-    size_t len = strlen(src);
+    size_t len = _strlen(src);
 
     if (len < n) {
-        memset(dst + len, 0x00, n - len);
-        memcpy(dst, src, len);
+        _memset(dst + len, 0x00, n - len);
+        _memcpy(dst, src, len);
     } else {
-        memcpy(dst, src, n);
+        _memcpy(dst, src, n);
     }
 
     return dst;
@@ -120,18 +96,18 @@ char* strncpy(char* dst, const char* src, size_t n)
 
 char* stpcpy(char* restrict dst, const char* restrict src)
 {
-    return memcpy(dst, src, strlen(src) + 1) + strlen(src);
+    return _memcpy(dst, src, _strlen(src) + 1) + _strlen(src);
 }
 
 char* stpncpy(char* restrict dst, const char* restrict src, size_t n)
 {
-    size_t len = strlen(src);
+    size_t len = _strlen(src);
 
     if (len < n) {
-        memset(dst + len, 0x00, n - len);
-        memcpy(dst, src, len);
+        _memset(dst + len, 0x00, n - len);
+        _memcpy(dst, src, len);
     } else {
-        memcpy(dst, src, n);
+        _memcpy(dst, src, n);
     }
 
     return dst + len;
@@ -259,14 +235,14 @@ char* strerror(int errnum)
 
 char* strndup(const char* str, size_t n)
 {
-    size_t len = strlen(str);
+    size_t len = _strlen(str);
     if (len > n)
         len = n;
     char* ret = malloc(len + 1);
     if (!ret)
         return NULL;
     
-    memcpy(ret, str, len);
+    _memcpy(ret, str, len);
     ret[len] = 0;
     return ret;
 }

+ 32 - 1
gblibstdc++/CMakeLists.txt

@@ -5,6 +5,37 @@ set(CMAKE_CXX_STANDARD 20)
 
 add_library(gblibstdc++ STATIC src/stdc++.cpp)
 
-file(GLOB_RECURSE GBSTDLIBCPP_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include)
+set(GBSTDLIBCPP_PUBLIC_HEADERS
+    gblibstdc++/include
+    gblibstdc++/include/bit
+    gblibstdc++/include/memory
+    gblibstdc++/include/tuple
+    gblibstdc++/include/type_traits
+    gblibstdc++/include/algorithm
+    gblibstdc++/include/cstddef
+    gblibstdc++/include/map
+    gblibstdc++/include/bits
+    gblibstdc++/include/bits/compressed_pair
+    gblibstdc++/include/bits/fwd_functional
+    gblibstdc++/include/bits/rbtree
+    gblibstdc++/include/bits/iter_ops
+    gblibstdc++/include/bits/type_traits
+    gblibstdc++/include/bits/type_traits/is_es
+    gblibstdc++/include/bits/type_traits/remove_add
+    gblibstdc++/include/bits/type_traits/base
+    gblibstdc++/include/bits/tuple_tools
+    gblibstdc++/include/bits/sequence
+    gblibstdc++/include/bits/forward
+    gblibstdc++/include/list
+    gblibstdc++/include/initializer_list
+    gblibstdc++/include/new
+    gblibstdc++/include/queue
+    gblibstdc++/include/string
+    gblibstdc++/include/set
+    gblibstdc++/include/vector
+    gblibstdc++/include/functional
+    gblibstdc++/include/utility
+    )
+
 target_include_directories(gblibstdc++ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
 set_target_properties(gblibstdc++ PROPERTIES PUBLIC_HEADER "${GBSTDLIBCPP_PUBLIC_HEADERS}")

+ 70 - 0
gblibstdc++/include/bits/compressed_pair

@@ -0,0 +1,70 @@
+#ifndef __GBLIBCPP_BITS_COMPRESSED_PAIR__
+#define __GBLIBCPP_BITS_COMPRESSED_PAIR__
+
+#include <utility>
+
+namespace std::impl {
+
+struct default_construct_t { };
+
+template <typename T, int, bool is_empty = __is_empty(T)>
+struct compressed_pair_element
+{
+    constexpr compressed_pair_element() = default;
+    constexpr compressed_pair_element(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element(compressed_pair_element&&) = default;
+    constexpr compressed_pair_element& operator=(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element& operator=(compressed_pair_element&&) = default;
+
+    constexpr compressed_pair_element(default_construct_t): value{} { }
+    constexpr compressed_pair_element(const T& x): value{x} { }
+    constexpr compressed_pair_element(T&& x): value{std::move(x)} { }
+
+    constexpr T& get() noexcept { return value; }
+    constexpr const T& get() const noexcept { return value; }
+
+    T value;
+};
+
+template <typename T, int N>
+struct compressed_pair_element<T, N, true> : private T
+{
+    constexpr compressed_pair_element() = default;
+    constexpr compressed_pair_element(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element(compressed_pair_element&&) = default;
+    constexpr compressed_pair_element& operator=(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element& operator=(compressed_pair_element&&) = default;
+
+    constexpr compressed_pair_element(default_construct_t): T{} { }
+    constexpr compressed_pair_element(const T& x): T{x} { }
+    constexpr compressed_pair_element(T&& x): T{std::move(x)} { }
+
+    constexpr T& get() noexcept { return *this; }
+    constexpr const T& get() const noexcept { return *this; }
+};
+
+template <typename T1, typename T2>
+struct compressed_pair
+    : private compressed_pair_element<T1, 0>, private compressed_pair_element<T2, 1> {
+    using Base1 = compressed_pair_element<T1, 0>;
+    using Base2 = compressed_pair_element<T2, 1>;
+
+    constexpr compressed_pair() = default;
+    constexpr compressed_pair(const compressed_pair&) = default;
+    constexpr compressed_pair(compressed_pair&&) = default;
+    constexpr compressed_pair& operator=(const compressed_pair&) = default;
+    constexpr compressed_pair& operator=(compressed_pair&&) = default;
+
+    constexpr compressed_pair(default_construct_t): Base1{default_construct_t{}}, Base2{default_construct_t{}} { }
+    constexpr compressed_pair(const T1& x, const T2& y): Base1{x}, Base2{y} { }
+    constexpr compressed_pair(T1&& x, T2&& y): Base1{std::move(x)}, Base2{std::move(y)} { }
+
+    constexpr T1& first() noexcept { return Base1::get(); }
+    constexpr const T1& first() const noexcept { return Base1::get(); }
+    constexpr T2& second() noexcept { return Base2::get(); }
+    constexpr const T2& second() const noexcept { return Base2::get(); }
+};
+
+} // namespace std::impl
+
+#endif

+ 84 - 71
gblibstdc++/include/bits/rbtree

@@ -1,6 +1,8 @@
 #ifndef __GBLIBCPP_BITS_RBTREE__
 #define __GBLIBCPP_BITS_RBTREE__
 
+#include "compressed_pair"
+
 #include <cstddef>
 #include <functional>
 #include <utility>
@@ -24,7 +26,7 @@ struct rbtree {
         constexpr node(T&& val)
             : parent {}, left {}, right {}
             , value { std::move(val) } , color {node_color::RED} {}
-        
+
         template <typename... Args, std::enable_if_t<
             (sizeof...(Args) > 1)
             || !(... && std::is_same_v<T, std::remove_cvref_t<Args>>)
@@ -237,9 +239,9 @@ struct rbtree {
         { p = p->prev(); return *this; }
         constexpr _iterator operator--(int)
         { _iterator ret(p); (void)this->operator--(); return ret; }
-        constexpr operator bool(void)
+        constexpr operator bool() const
         { return p; }
-        constexpr operator _iterator<true>()
+        constexpr operator _iterator<true>() const
         { return _iterator<true> { p }; }
     };
 
@@ -250,24 +252,34 @@ struct rbtree {
         std::allocator_traits<Allocator>::template rebind_alloc<node>;
     using node_alloc_traits = std::allocator_traits<node_allocator>;
 
-    node* root;
-    node_allocator alloc;
-    std::size_t _size;
-    Compare comp;
+    compressed_pair<node*, node_allocator> root_data;
+    compressed_pair<std::size_t, Compare> size_data;
 
 private:
+    constexpr node*& _root() noexcept { return root_data.first(); }
+    constexpr node* const& _root() const noexcept { return root_data.first(); }
+
+    constexpr std::size_t& _size() noexcept { return size_data.first(); }
+    constexpr const std::size_t& _size() const noexcept { return size_data.first(); }
+
+    constexpr node_allocator& _alloc() noexcept { return root_data.second(); }
+    constexpr const node_allocator& _alloc() const noexcept { return root_data.second(); }
+
+    constexpr Compare& _comp() noexcept { return size_data.second(); }
+    constexpr const Compare& _comp() const noexcept { return size_data.second(); }
+
     template <typename... Args>
     constexpr node* newnode(Args&&... key)
     {
-        node* ptr = node_alloc_traits::allocate(alloc, 1);
-        node_alloc_traits::construct(alloc, ptr, std::forward<Args>(key)...);
+        node* ptr = node_alloc_traits::allocate(_alloc(), 1);
+        node_alloc_traits::construct(_alloc(), ptr, std::forward<Args>(key)...);
         return ptr;
     }
 
     constexpr void delnode(node* nd)
     {
-        node_alloc_traits::destroy(alloc, nd);
-        node_alloc_traits::deallocate(alloc, nd, 1);
+        node_alloc_traits::destroy(_alloc(), nd);
+        node_alloc_traits::deallocate(_alloc(), nd, 1);
     }
 
     constexpr void do_insertion(node* parent,
@@ -276,7 +288,7 @@ private:
         nd->parent = parent;
         child_inserted = nd;
         this->balance(nd);
-        ++_size;
+        ++_size();
     }
 
 public:
@@ -288,11 +300,11 @@ public:
     { return const_iterator(nullptr); }
 
     constexpr iterator begin(void) noexcept
-    { return root ? iterator(root->leftmost()) : end(); }
+    { return _root() ? iterator(_root()->leftmost()) : end(); }
     constexpr const_iterator begin(void) const noexcept
-    { return root ? const_iterator(root->leftmost()) : end(); }
+    { return _root() ? const_iterator(_root()->leftmost()) : end(); }
     constexpr const_iterator cbegin(void) const noexcept
-    { return root ? const_iterator(root->leftmost()) : end(); }
+    { return _root() ? const_iterator(_root()->leftmost()) : end(); }
 
     constexpr void destroy(node* nd)
     {
@@ -303,7 +315,7 @@ public:
         delnode(nd);
     }
 
-    constexpr void destroy() { destroy(root); root = nullptr; _size = 0; }
+    constexpr void destroy() { destroy(_root()); _root() = nullptr; _size() = 0; }
 
     constexpr node* copy(node* nd)
     {
@@ -312,74 +324,75 @@ public:
 
         node* newnd = newnode(nd->value);
         newnd->color = nd->color;
-        ++_size;
+        ++_size();
 
         newnd->left = copy(nd->left);
         if (newnd->left)
-            newnd->left->parent = newnd->left;
+            newnd->left->parent = newnd;
 
         newnd->right = copy(nd->right);
         if (newnd->right)
-            newnd->right->parent = newnd->right;
+            newnd->right->parent = newnd;
 
         return newnd;
     }
 
     explicit constexpr rbtree(const Compare& comp, const node_allocator& alloc)
-        : root(), alloc(alloc), _size(), comp(comp) {}
+        : root_data{nullptr, alloc}, size_data{0, comp} { }
 
     constexpr rbtree(const rbtree& other)
-        : rbtree(other.comp, other.alloc)
+        : rbtree(other._comp(), other._alloc())
     {
-        root = copy(other.root);
-        if (root)
-            root->parent = nullptr;
+        _root() = copy(other._root());
+        if (_root())
+            _root()->parent = nullptr;
     }
 
     constexpr rbtree(const rbtree& other, const node_allocator& alloc)
-        : rbtree(other.comp, alloc)
+        : rbtree(other._comp(), alloc)
     {
-        root = copy(other.root);
-        if (root)
-            root->parent = nullptr;
+        _root() = copy(other._root());
+        if (_root())
+            _root()->parent = nullptr;
     }
-    
+
     constexpr rbtree(rbtree&& other) noexcept
-        : root(std::exchange(other.root, nullptr))
-        , alloc(std::move(other.alloc))
-        , _size(std::exchange(other._size, 0))
-        , comp(std::move(other.comp)) {}
+        : root_data{std::exchange(other._root(), nullptr), std::move(other._alloc())}
+        , size_data{std::exchange(other._size(), 0), std::move(other._comp())} { }
 
     constexpr rbtree(rbtree&& other, const node_allocator& alloc) noexcept
-        : root(std::exchange(other.root, nullptr))
-        , alloc(alloc) , _size(std::exchange(other._size, 0))
-        , comp(std::move(other.comp)) {}
-    
+        : root_data{std::exchange(other._root(), nullptr), alloc}
+        , size_data{std::exchange(other._size(), 0), std::move(other._comp())} { }
+
     constexpr ~rbtree() { destroy(); }
 
     constexpr rbtree& operator=(const rbtree& other)
     {
-        destroy(root);
+        destroy(_root());
 
-        comp = other.comp;
+        _comp() = other._comp();
         if constexpr (node_alloc_traits::
             propagate_on_container_copy_assignment::value)
-            alloc = other.alloc;
+            _alloc() = other._alloc();
+
+        _root() = copy(other._root());
+        if (_root())
+            _root()->parent = nullptr;
 
-        root = copy(other.root);
-        if (root)
-            root->parent = nullptr;
+        return *this;
     }
-    
+
     constexpr rbtree& operator=(rbtree&& other) noexcept
     {
-        destroy(root);
-        root = std::exchange(other.root, nullptr);
-        _size = std::exchange(other._size, 0);
-        comp = std::move(other.comp);
+        destroy(_root());
+        _root() = std::exchange(other._root(), nullptr);
+        _size() = std::exchange(other._size(), 0);
+        _comp() = std::move(other._comp());
         if constexpr (node_alloc_traits::
             propagate_on_container_move_assignment::value)
-            alloc = std::move(other.alloc);
+            _alloc() = std::move(other._alloc());
+
+        return *this;
     }
 
     constexpr void rotateleft(node* rt)
@@ -392,7 +405,7 @@ public:
             else
                 rt->parent->right = nrt;
         } else {
-            this->root = nrt;
+            _root() = nrt;
         }
 
         nrt->parent = rt->parent;
@@ -415,7 +428,7 @@ public:
             else
                 rt->parent->right = nrt;
         } else {
-            this->root = nrt;
+            _root() = nrt;
         }
 
         nrt->parent = rt->parent;
@@ -473,10 +486,10 @@ public:
     template <typename U>
     constexpr node* _find(const U& key) const
     {
-        for (node* cur = root; cur; ) {
-            if (comp(key, cur->value))
+        for (node* cur = _root(); cur; ) {
+            if (_comp()(key, cur->value))
                 cur = cur->left;
-            else if (comp(cur->value, key))
+            else if (_comp()(cur->value, key))
                 cur = cur->right;
             else
                 return cur;
@@ -561,7 +574,7 @@ public:
     constexpr node* erase(node* nd)
     {
         if (nd->is_root() && nd->is_leaf()) {
-            root = nullptr;
+            _root() = nullptr;
             return nullptr;
         }
 
@@ -570,7 +583,7 @@ public:
         while (!nd->is_leaf()) {
             node* alt = nd->right ? nd->right->leftmost() : nd->left;
             if (nd->is_root())
-                this->root = alt;
+                _root() = alt;
             node::swap(nd, alt);
         }
 
@@ -588,7 +601,7 @@ public:
     {
         node* nextpos = erase(pos.p);
         delnode(pos.p);
-        --_size;
+        --_size();
         return iterator { nextpos };
     }
 
@@ -596,18 +609,18 @@ public:
     {
         node* nextpos = erase(pos.p);
         delnode(pos.p);
-        --_size;
-        return const_iterator { nextpos };
+        --_size();
+        return iterator { nextpos };
     }
 
     template <typename U>
     constexpr iterator lower_bound(U&& val) const
     {
-        node* cur = root;
+        node* cur = _root();
         node* result = nullptr;
 
         while (cur) {
-            if (!comp(cur->value, val)) {
+            if (!_comp()(cur->value, val)) {
                 result = cur;
                 cur = cur->left;
             }
@@ -623,7 +636,7 @@ public:
     constexpr iterator upper_bound(U&& val) const
     {
         iterator iter = lower_bound(std::forward<U>(val));
-        if (iter && !comp(*iter, val) && !comp(val, *iter))
+        if (iter && !_comp()(*iter, val) && !_comp()(val, *iter))
             return ++iter;
         return iter;
     }
@@ -632,10 +645,10 @@ public:
     // that is, if a < b, then a > b
     constexpr void insert(node* nd)
     {
-        node* cur = root;
+        node* cur = _root();
 
         while (cur) {
-            if (comp(nd->value, cur->value)) {
+            if (_comp()(nd->value, cur->value)) {
                 if (!cur->left) {
                     do_insertion(cur, cur->left, nd);
                     return;
@@ -649,7 +662,7 @@ public:
                 cur = cur->right;
             }
         }
-        do_insertion(cur, root, nd);
+        do_insertion(cur, _root(), nd);
     }
 
     template <typename U>
@@ -678,16 +691,16 @@ public:
         return { iterator { nd }, true };
     }
 
-    constexpr bool empty() const noexcept { return !root; }
-    constexpr std::size_t size() const noexcept { return _size; }
+    constexpr bool empty() const noexcept { return !_root(); }
+    constexpr std::size_t size() const noexcept { return _size(); }
 
     constexpr void swap(rbtree& other)
     {
-        std::swap(root, other.root);
-        std::swap(_size, other._size);
-        std::swap(comp, other.comp);
+        std::swap(_root(), other._root());
+        std::swap(_size(), other._size());
+        std::swap(_comp(), other._comp());
         if constexpr (node_alloc_traits::propagate_on_container_swap::value)
-            std::swap(alloc, other.alloc);
+            std::swap(_alloc(), other._alloc());
     }
 };
 

+ 5 - 8
gblibstdc++/include/functional

@@ -38,7 +38,7 @@ class reference_wrapper {
 private:
     T* _ptr;
 
-    template <typename Ref, typename = 
+    template <typename Ref, typename =
         decltype(__helpers::__reference_wrapper_check<T>(std::declval<Ref>()))>
     struct __check_reference_valid
         : public bool_constant<!std::is_same_v<reference_wrapper, std::decay_t<Ref>>> {};
@@ -87,8 +87,7 @@ namespace __inner {
     class _function : public _function_base<Ret, Args...> {
     private:
         using __enable = std::enable_if_t<
-            std::is_same_v<Ret,
-                decltype(std::declval<std::decay_t<FuncLike>>()(std::declval<Args>()...))>
+            std::is_invocable_r_v<Ret, std::decay_t<FuncLike>, Args...>
         >;
         FuncLike func;
 
@@ -148,7 +147,7 @@ public:
     using result_type = Ret;
 
 private:
-    static constexpr std::size_t STACK_ALLOCATED_SIZE = 12;
+    static constexpr std::size_t STACK_ALLOCATED_SIZE = 24;
 
     char _data[STACK_ALLOCATED_SIZE];
     using fb_t = __inner::_function_base<Ret, Args...>;
@@ -179,10 +178,8 @@ public:
 
     template <typename FuncLike, std::enable_if_t
         <
-            std::is_same_v<
-                Ret,
-                decltype(std::declval<std::decay_t<FuncLike>>()(std::declval<Args>()...))
-            >
+            // TODO: check its behavior for nullptr
+            std::is_invocable_r_v<Ret, std::decay_t<FuncLike>, Args...>
             && (sizeof(std::decay_t<FuncLike>) <= STACK_ALLOCATED_SIZE - sizeof(void*))
             && !std::is_same_v<std::decay_t<FuncLike>, function>
         , bool> = true

+ 43 - 50
gblibstdc++/include/list

@@ -1,6 +1,7 @@
 #ifndef __GBLIBCPP_LIST__
 #define __GBLIBCPP_LIST__
 
+#include <bits/compressed_pair>
 #include <bits/iter_ops>
 
 #include <memory>
@@ -11,8 +12,7 @@
 
 namespace std {
 
-template <typename T,
-    typename Allocator = std::allocator<T>>
+template <typename T, typename Allocator = std::allocator<T>>
 class list {
 private:
     struct node_base {
@@ -75,7 +75,7 @@ public:
         using reference = std::add_lvalue_reference_t<value_type>;
 
         friend class list;
-    
+
     private:
         node_pointer p;
 
@@ -104,26 +104,31 @@ public:
         { p = p->prev; return *this; }
         constexpr _iterator operator--(int) noexcept
         { _iterator ret(p); (void)this->operator--(); return ret; }
-        constexpr operator bool() { return p; }
-        constexpr operator _iterator<true>() { return _iterator<true> { p }; }
+        constexpr operator bool() const { return p; }
+        constexpr operator _iterator<true>() const { return _iterator<true> { p }; }
     };
 
 private:
     node_base m_head;
-    size_type m_size;
-    node_alloc_type m_alloc;
+    impl::compressed_pair<size_type, node_alloc_type> m_pair;
 
 private:
     // move m_head and m_size of other to *this
     // other MUST NOT be empty, *this MUST be empty
     constexpr void _move_from(list&& other) noexcept
     {
-        std::swap(m_size, other.m_size);
+        std::swap(_size(), other._size());
         other.m_head.prev->connect(&m_head);
         m_head.connect(other.m_head.next);
         other.m_head.next = other.m_head.prev = &other.m_head;
     }
 
+    constexpr size_type& _size() noexcept { return m_pair.first(); }
+    constexpr const size_type& _size() const noexcept { return m_pair.first(); }
+
+    constexpr node_alloc_type& _alloc() noexcept { return m_pair.second(); }
+    constexpr const node_alloc_type& _alloc() const noexcept { return m_pair.second(); }
+
 public:
     __GBLIBCPP_CONSTEXPR
     iterator end(void) noexcept { return iterator { &m_head }; }
@@ -144,38 +149,33 @@ public:
     __GBLIBCPP_CONSTEXPR
     iterator emplace(const_iterator pos, Args&&... args)
     {
-        node* nd = node_alloc_traits::allocate(m_alloc, 1);
-        node_alloc_traits::construct(m_alloc, nd, std::forward<Args>(args)...);
+        node* nd = node_alloc_traits::allocate(_alloc(), 1);
+        node_alloc_traits::construct(_alloc(), nd, std::forward<Args>(args)...);
 
         nd->next = pos.p;
         nd->prev = pos.p->prev;
         nd->next->prev = nd;
         nd->prev->next = nd;
 
-        ++m_size;
+        ++_size();
         return iterator { nd };
     }
-    
+
     explicit __GBLIBCPP_CONSTEXPR
-    list(const Allocator& alloc)
-        : m_head { }, m_size { }, m_alloc(alloc) { }
+    list(const Allocator& alloc): m_head{}, m_pair{0, alloc} { }
 
     __GBLIBCPP_CONSTEXPR
-    list() : list(Allocator()) {}
+    list(): list(Allocator()) {}
 
     __GBLIBCPP_CONSTEXPR
-    explicit list(size_type count,
-        const Allocator& alloc = Allocator())
-        : list(alloc)
+    explicit list(size_type count, const Allocator& alloc = Allocator()): list(alloc)
     {
         while (count--)
             emplace_back();
     }
 
     __GBLIBCPP_CONSTEXPR
-    list(size_type count, const T& value,
-        const Allocator& alloc = Allocator())
-        : list(alloc)
+    list(size_type count, const T& value, const Allocator& alloc = Allocator()): list(alloc)
     {
         while (count--)
             emplace_back(value);
@@ -183,28 +183,22 @@ public:
 
     template <typename InputIter>
     __GBLIBCPP_CONSTEXPR
-    list(InputIter first, InputIter last,
-        const Allocator& alloc = Allocator())
+    list(InputIter first, InputIter last, const Allocator& alloc = Allocator())
         : list(alloc) { insert(first, last); }
 
     __GBLIBCPP_CONSTEXPR
-    list(const list& other, const Allocator& alloc)
-        : list(alloc)
+    list(const list& other, const Allocator& alloc): list(alloc)
     {
         // TODO: select_on_container_copy_construction
         for (const auto& item : other)
             emplace_back(item);
     }
     __GBLIBCPP_CONSTEXPR
-    list(const list& other)
-        : list(other,
-            alloc_traits::select_on_container_copy_construction(m_alloc))
-    { }
+    list(const list& other): list(other,
+            alloc_traits::select_on_container_copy_construction(_alloc())) { }
 
     __GBLIBCPP_CONSTEXPR
-    list(list&& other)
-        : m_head { }, m_size { }
-        , m_alloc(std::move(other.m_alloc))
+    list(list&& other): m_head{}, m_pair{0, std::move(other._alloc())}
     {
         if (other.empty())
             return;
@@ -212,16 +206,15 @@ public:
     }
 
     __GBLIBCPP_CONSTEXPR
-    list(list&& other, const Allocator& alloc)
-        : m_head { }, m_size { }, m_alloc(alloc)
+    list(list&& other, const Allocator& alloc): m_head{}, m_pair{0, alloc}
     {
-        if (other.m_alloc != alloc) {
+        if (other._alloc() != alloc) {
             for (auto iter = other.begin(); iter != other.end(); ++iter)
                 emplace(cend(), std::move(*iter));
             other.clear();
             return;
         }
-        // other.m_alloc == alloc
+        // other._alloc() == alloc
         if (other.empty())
             return;
 
@@ -236,23 +229,23 @@ public:
         for (const auto& item : ilist)
             emplace_back(item);
     }
-    
+
     __GBLIBCPP_CONSTEXPR
     ~list()
     {
         clear();
         m_head.next = m_head.prev = nullptr;
     }
-    
+
     __GBLIBCPP_CONSTEXPR
     list& operator=(const list& other)
     {
-        // TODO: reuse memory if m_alloc == other.m_alloc
+        // TODO: reuse memory if _alloc() == other._alloc()
         clear();
 
         if constexpr (alloc_traits::
             propagate_on_container_copy_assignment::value)
-            m_alloc = other.m_alloc;
+            _alloc() = other._alloc();
 
         for (const auto& item : other)
             emplace_back(item);
@@ -265,7 +258,7 @@ public:
         if (alloc_traits::
             propagate_on_container_move_assignment::value) {
             clear();
-            m_alloc = std::move(other.m_alloc);
+            _alloc() = std::move(other._alloc());
 
             if (other.empty())
                 return *this;
@@ -274,10 +267,10 @@ public:
             return *this;
         }
 
-        // TODO: reuse memory if m_alloc == other.m_alloc
+        // TODO: reuse memory if _alloc() == other._alloc()
         clear();
 
-        if (m_alloc != other.m_alloc) {
+        if (_alloc() != other._alloc()) {
             for (auto iter = other.begin(); iter != other.end(); ++iter)
                 emplace(cend(), std::move(*iter));
             other.clear();
@@ -323,7 +316,7 @@ public:
     }
 
     __GBLIBCPP_CONSTEXPR
-    allocator_type get_allocator() const noexcept { return m_alloc; }
+    allocator_type get_allocator() const noexcept { return _alloc(); }
 
     __GBLIBCPP_CONSTEXPR
     reference front() { return *begin(); }
@@ -398,10 +391,10 @@ public:
         pos.p->next->prev = pos.p->prev;
         pos.p->prev->next = pos.p->next;
 
-        node_alloc_traits::destroy(m_alloc, (node*)pos.p);
-        node_alloc_traits::deallocate(m_alloc, (node*)pos.p, 1);
+        node_alloc_traits::destroy(_alloc(), (node*)pos.p);
+        node_alloc_traits::deallocate(_alloc(), (node*)pos.p, 1);
 
-        --m_size;
+        --_size();
         return ret;
     }
 
@@ -421,7 +414,7 @@ public:
     }
 
     __GBLIBCPP_CONSTEXPR
-    size_type size() const noexcept { return m_size; }
+    size_type size() const noexcept { return _size(); }
 
     __GBLIBCPP_CONSTEXPR
     bool empty() const noexcept { return size() == 0; }
@@ -430,9 +423,9 @@ public:
     void swap(list& other)
     {
         if constexpr (alloc_traits::propagate_on_container_swap::value)
-            std::swap(m_alloc, other.m_alloc);
+            std::swap(_alloc(), other._alloc());
 
-        std::swap(m_size, other.m_size);
+        std::swap(_size(), other.m_size);
         std::swap(m_head, other.m_head);
         std::swap(m_head.next->prev, other.m_head.next->prev);
         std::swap(m_head.prev->next, other.m_head.prev->next);

+ 11 - 12
gblibstdc++/include/map

@@ -26,25 +26,24 @@ public:
     using allocator_type = Allocator;
 
 private:
-    class value_compare {
+    class value_compare : public Compare {
     protected:
-        Compare comp;
-        constexpr value_compare(Compare c) : comp(c) {}
+        constexpr value_compare(Compare c): Compare{c} {}
 
         friend class map;
 
     public:
         constexpr bool operator()(
             const value_type& lhs, const value_type& rhs) const
-        { return comp(lhs.first, rhs.first); }
+        { return Compare::operator()(lhs.first, rhs.first); }
 
         constexpr bool operator()(
             const Key& lhs, const value_type& rhs) const
-        { return comp(lhs, rhs.first); }
+        { return Compare::operator()(lhs, rhs.first); }
 
         constexpr bool operator()(
             const value_type& lhs, const Key& rhs) const
-        { return comp(lhs.first, rhs); }
+        { return Compare::operator()(lhs.first, rhs); }
     };
 
     using rbtree_type = impl::rbtree<value_type, value_compare, Allocator>;
@@ -76,7 +75,7 @@ public:
     map(const Compare& comp,
         const Allocator& alloc = Allocator())
         : tree(comp, alloc) {}
-    
+
     explicit __GBLIBCPP_CONSTEXPR
     map(const Allocator& alloc)
         : map(Compare(), alloc) {}
@@ -101,17 +100,17 @@ public:
         : map(first, last, Compare(), alloc) {}
 
     __GBLIBCPP_CONSTEXPR
-    map(const map& other) : tree(other) {}
+    map(const map& other) : tree(other.tree) {}
     __GBLIBCPP_CONSTEXPR
     map(const map& other, const Allocator& alloc)
-        : tree(other, alloc) { }
+        : tree(other.tree, alloc) { }
 
     __GBLIBCPP_CONSTEXPR
     map(map&& other) : tree(std::move(other.tree)) {}
     __GBLIBCPP_CONSTEXPR
     map(map&& other, const Allocator& alloc)
         : tree(std::move(other.tree), alloc) {}
-    
+
     __GBLIBCPP_CONSTEXPR
     map(std::initializer_list<value_type> init,
         const Compare& comp = Compare(),
@@ -123,10 +122,10 @@ public:
     map(std::initializer_list<value_type> init,
         const Allocator& alloc)
         : map(init, Compare(), alloc) {}
-    
+
     __GBLIBCPP_CONSTEXPR
     ~map() { clear(); }
-    
+
     __GBLIBCPP_CONSTEXPR
     map& operator=(const map& other) = default;
     __GBLIBCPP_CONSTEXPR

+ 506 - 383
gblibstdc++/include/memory

@@ -1,16 +1,16 @@
 #ifndef __GBLIBCPP_MEMORY__
 #define __GBLIBCPP_MEMORY__
 
+#include <bits/compressed_pair>
 #include <cstddef>
+#include <new>
 #include <type_traits>
 #include <utility>
-#include <new>
 
 namespace std {
 
 template <typename T>
-constexpr T* addressof(T& arg) noexcept
-{
+constexpr T* addressof(T& arg) noexcept {
     return __builtin_addressof(arg);
 }
 
@@ -37,79 +37,87 @@ const T* addressof(const T&&) = delete;
 
 namespace __helpers {
 
-template <typename Ptr, typename = void>
-struct pointer_difference_type
-{ using type = std::ptrdiff_t; };
+    template <typename Ptr, typename = void>
+    struct pointer_difference_type {
+        using type = std::ptrdiff_t;
+    };
 
-template <typename Ptr>
-struct pointer_difference_type<Ptr,
-    std::void_t<typename Ptr::difference_type>>
-{ using type = typename Ptr::difference_type; };
+    template <typename Ptr>
+    struct pointer_difference_type<Ptr,
+                                   std::void_t<typename Ptr::difference_type>> {
+        using type = typename Ptr::difference_type;
+    };
 
-template <typename Ptr>
-using pointer_difference_type_t =
-    typename pointer_difference_type<Ptr>::type;
+    template <typename Ptr>
+    using pointer_difference_type_t =
+        typename pointer_difference_type<Ptr>::type;
 
-template <typename Base, typename T>
-struct rebind;
+    template <typename Base, typename T>
+    struct rebind;
 
-template <template <typename, typename...> typename Template,
-    typename NewType, typename OldType, typename... Args>
-struct rebind<Template<OldType, Args...>, NewType> {
-    using type = Template<NewType, Args...>;
-};
+    template <template <typename, typename...> typename Template,
+              typename NewType, typename OldType, typename... Args>
+    struct rebind<Template<OldType, Args...>, NewType> {
+        using type = Template<NewType, Args...>;
+    };
 
-template <typename Ptr, typename T, typename = void>
-struct try_rebind { using type = typename rebind<Ptr, T>::type; };
+    template <typename Ptr, typename T, typename = void>
+    struct try_rebind {
+        using type = typename rebind<Ptr, T>::type;
+    };
 
-template <typename Ptr, typename T>
-struct try_rebind<Ptr, T,
-    std::void_t<typename Ptr::template rebind<T>>> {
-    using type = typename Ptr::template rebind<T>;
-};
+    template <typename Ptr, typename T>
+    struct try_rebind<Ptr, T, std::void_t<typename Ptr::template rebind<T>>> {
+        using type = typename Ptr::template rebind<T>;
+    };
 
-template <typename Ptr, typename = void>
-struct pointer_element {};
+    template <typename Ptr, typename = void>
+    struct pointer_element {};
 
-template <typename Ptr>
-struct pointer_element<Ptr, std::enable_if_t<
-    std::is_same_v<void, std::void_t<typename Ptr::element_type>>
->> { using type = typename Ptr::element_type; };
+    template <typename Ptr>
+    struct pointer_element<
+        Ptr, std::enable_if_t<std::is_same_v<
+                 void, std::void_t<typename Ptr::element_type>>>> {
+        using type = typename Ptr::element_type;
+    };
 
-template <template <typename, typename...> typename Template,
-    typename T, typename... Args>
-struct pointer_element<Template<T, Args...>, void>
-{ using type = T; };
+    template <template <typename, typename...> typename Template, typename T,
+              typename... Args>
+    struct pointer_element<Template<T, Args...>, void> {
+        using type = T;
+    };
 
-template <typename Ptr, typename = void>
-struct pointer_traits_impl {};
+    template <typename Ptr, typename = void>
+    struct pointer_traits_impl {};
 
-template <typename Ptr>
-struct pointer_traits_impl<Ptr,
-    std::void_t<typename pointer_element<Ptr>::type>> {
-    using pointer = Ptr;
-    using element_type = typename pointer_element<Ptr>::type;
-    using difference_type = pointer_difference_type_t<Ptr>;
+    template <typename Ptr>
+    struct pointer_traits_impl<
+        Ptr, std::void_t<typename pointer_element<Ptr>::type>> {
+        using pointer = Ptr;
+        using element_type = typename pointer_element<Ptr>::type;
+        using difference_type = pointer_difference_type_t<Ptr>;
 
-    template <typename U>
-    using rebind = typename try_rebind<Ptr, U>::type;
+        template <typename U>
+        using rebind = typename try_rebind<Ptr, U>::type;
 
-    static pointer pointer_to(element_type& ref)
-    { return Ptr::pointer_to(ref); }
-};
+        static pointer pointer_to(element_type& ref) {
+            return Ptr::pointer_to(ref);
+        }
+    };
 
-template <typename T>
-struct pointer_traits_impl<T*, void> {
-    using pointer = T*;
-    using element_type = T;
-    using difference_type = std::ptrdiff_t;
+    template <typename T>
+    struct pointer_traits_impl<T*, void> {
+        using pointer = T*;
+        using element_type = T;
+        using difference_type = std::ptrdiff_t;
 
-    template <typename U>
-    using rebind = U*;
+        template <typename U>
+        using rebind = U*;
 
-    static pointer pointer_to(element_type& ref)
-    { return std::addressof(ref); }
-};
+        static pointer pointer_to(element_type& ref) {
+            return std::addressof(ref);
+        }
+    };
 
 } // namespace __helpers
 
@@ -118,160 +126,170 @@ struct pointer_traits : public __helpers::pointer_traits_impl<Ptr> {};
 
 namespace __helpers {
 
-template <typename Alloc, typename = void>
-struct allocator_pointer
-{ using type = typename Alloc::value_type*; };
+    template <typename Alloc, typename = void>
+    struct allocator_pointer {
+        using type = typename Alloc::value_type*;
+    };
 
-template <typename Alloc>
-struct allocator_pointer<Alloc,
-    std::void_t<typename Alloc::pointer>>
-{ using type = typename Alloc::pointer; };
+    template <typename Alloc>
+    struct allocator_pointer<Alloc, std::void_t<typename Alloc::pointer>> {
+        using type = typename Alloc::pointer;
+    };
 
-template <typename Alloc>
-using allocator_pointer_t =
-    typename allocator_pointer<Alloc>::type;
+    template <typename Alloc>
+    using allocator_pointer_t = typename allocator_pointer<Alloc>::type;
 
+    template <typename Alloc, typename Pointer, typename = void>
+    struct allocator_const_pointer {
+        using type = typename std::pointer_traits<Pointer>::template rebind<
+            const typename Alloc::value_type>;
+    };
 
-template <typename Alloc, typename Pointer, typename = void>
-struct allocator_const_pointer {
-    using type = typename std::pointer_traits<Pointer>::template
-        rebind<const typename Alloc::value_type>;
-};
+    template <typename Alloc, typename Pointer>
+    struct allocator_const_pointer<Alloc, Pointer,
+                                   std::void_t<typename Alloc::const_pointer>> {
+        using type = typename Alloc::const_pointer;
+    };
 
-template <typename Alloc, typename Pointer>
-struct allocator_const_pointer<Alloc, Pointer,
-    std::void_t<typename Alloc::const_pointer>>
-{ using type = typename Alloc::const_pointer; };
+    template <typename Alloc, typename Pointer>
+    using allocator_const_pointer_t =
+        typename allocator_const_pointer<Alloc, Pointer>::type;
 
-template <typename Alloc, typename Pointer>
-using allocator_const_pointer_t =
-    typename allocator_const_pointer<Alloc, Pointer>::type;
+    template <typename Alloc, typename Pointer, typename = void>
+    struct allocator_void_pointer {
+        using type =
+            typename std::pointer_traits<Pointer>::template rebind<void>;
+    };
 
+    template <typename Alloc, typename Pointer>
+    struct allocator_void_pointer<Alloc, Pointer,
+                                  std::void_t<typename Alloc::void_pointer>> {
+        using type = typename Alloc::void_pointer;
+    };
 
-template <typename Alloc, typename Pointer, typename = void>
-struct allocator_void_pointer {
-    using type = typename std::pointer_traits<Pointer>::template
-        rebind<void>;
-};
+    template <typename Alloc, typename Pointer>
+    using allocator_void_pointer_t =
+        typename allocator_void_pointer<Alloc, Pointer>::type;
 
-template <typename Alloc, typename Pointer>
-struct allocator_void_pointer<Alloc, Pointer,
-    std::void_t<typename Alloc::void_pointer>>
-{ using type = typename Alloc::void_pointer; };
+    template <typename Alloc, typename Pointer, typename = void>
+    struct allocator_const_void_pointer {
+        using type =
+            typename std::pointer_traits<Pointer>::template rebind<const void>;
+    };
 
-template <typename Alloc, typename Pointer>
-using allocator_void_pointer_t =
-    typename allocator_void_pointer<Alloc, Pointer>::type;
+    template <typename Alloc, typename Pointer>
+    struct allocator_const_void_pointer<
+        Alloc, Pointer, std::void_t<typename Alloc::const_void_pointer>> {
+        using type = typename Alloc::const_void_pointer;
+    };
 
+    template <typename Alloc, typename Pointer>
+    using allocator_const_void_pointer_t =
+        typename allocator_const_void_pointer<Alloc, Pointer>::type;
 
-template <typename Alloc, typename Pointer, typename = void>
-struct allocator_const_void_pointer {
-    using type = typename std::pointer_traits<Pointer>::template
-        rebind<const void>;
-};
+    template <typename Alloc, typename = void>
+    struct allocator_difference_type {
+        using type = std::ptrdiff_t;
+    };
+    template <typename Alloc>
+    struct allocator_difference_type<
+        Alloc, std::void_t<typename Alloc::difference_type>> {
+        using type = typename Alloc::difference_type;
+    };
+    template <typename Alloc>
+    using allocator_difference_type_t =
+        typename allocator_difference_type<Alloc>::type;
 
-template <typename Alloc, typename Pointer>
-struct allocator_const_void_pointer<Alloc, Pointer,
-    std::void_t<typename Alloc::const_void_pointer>>
-{ using type = typename Alloc::const_void_pointer; };
-
-template <typename Alloc, typename Pointer>
-using allocator_const_void_pointer_t =
-    typename allocator_const_void_pointer<Alloc, Pointer>::type;
-
-
-template <typename Alloc, typename = void>
-struct allocator_difference_type
-{ using type = std::ptrdiff_t; };
-template <typename Alloc>
-struct allocator_difference_type<Alloc,
-    std::void_t<typename Alloc::difference_type>>
-{ using type = typename Alloc::difference_type; };
-template <typename Alloc>
-using allocator_difference_type_t =
-    typename allocator_difference_type<Alloc>::type;
-
-template <typename Alloc, typename = void>
-struct allocator_size_type
-{ using type = std::size_t; };
-template <typename Alloc>
-struct allocator_size_type<Alloc,
-    std::void_t<typename Alloc::size_type>>
-{ using type = typename Alloc::size_type; };
-template <typename Alloc>
-using allocator_size_type_t =
-    typename allocator_size_type<Alloc>::type;
-
-template <typename Alloc, typename = void>
-struct allocator_prop_copy
-{ using type = std::false_type; };
-template <typename Alloc>
-struct allocator_prop_copy<Alloc,
-    std::void_t<typename Alloc::propagate_on_container_copy_assignment>>
-{ using type = typename Alloc::propagate_on_container_copy_assignment; };
-template <typename Alloc>
-using allocator_prop_copy_t =
-    typename allocator_prop_copy<Alloc>::type;
-
-template <typename Alloc, typename = void>
-struct allocator_prop_move
-{ using type = std::false_type; };
-template <typename Alloc>
-struct allocator_prop_move<Alloc,
-    std::void_t<typename Alloc::propagate_on_container_move_assignment>>
-{ using type = typename Alloc::propagate_on_container_move_assignment; };
-template <typename Alloc>
-using allocator_prop_move_t =
-    typename allocator_prop_move<Alloc>::type;
-
-template <typename Alloc, typename = void>
-struct allocator_prop_swap
-{ using type = std::false_type; };
-template <typename Alloc>
-struct allocator_prop_swap<Alloc,
-    std::void_t<typename Alloc::propagate_on_container_swap>>
-{ using type = typename Alloc::propagate_on_container_swap; };
-template <typename Alloc>
-using allocator_prop_swap_t =
-    typename allocator_prop_swap<Alloc>::type;
-
-template <typename Alloc, typename = void>
-struct is_always_equal
-{ using type = std::false_type; };
-template <typename Alloc>
-struct is_always_equal<Alloc,
-    std::void_t<typename Alloc::is_always_equal>>
-{ using type = typename Alloc::is_always_equal; };
-template <typename Alloc>
-using is_always_equal_t =
-    typename is_always_equal<Alloc>::type;
-
-template <typename Alloc, typename = void>
-struct allocator_select_on_copy {
-    static constexpr Alloc get(const Alloc& alloc)
-    { return alloc; }
-};
+    template <typename Alloc, typename = void>
+    struct allocator_size_type {
+        using type = std::size_t;
+    };
+    template <typename Alloc>
+    struct allocator_size_type<Alloc, std::void_t<typename Alloc::size_type>> {
+        using type = typename Alloc::size_type;
+    };
+    template <typename Alloc>
+    using allocator_size_type_t = typename allocator_size_type<Alloc>::type;
 
-template <typename Alloc>
-struct allocator_select_on_copy<Alloc, std::enable_if_t<
-    std::is_same_v<void, std::void_t<decltype(
-        std::declval<Alloc>().select_on_container_copy_construction()
-    )>> >> {
-    static constexpr Alloc get(const Alloc& alloc)
-    { return alloc.select_on_container_copy_construction(); }
-};
+    template <typename Alloc, typename = void>
+    struct allocator_prop_copy {
+        using type = std::false_type;
+    };
+    template <typename Alloc>
+    struct allocator_prop_copy<
+        Alloc,
+        std::void_t<typename Alloc::propagate_on_container_copy_assignment>> {
+        using type = typename Alloc::propagate_on_container_copy_assignment;
+    };
+    template <typename Alloc>
+    using allocator_prop_copy_t = typename allocator_prop_copy<Alloc>::type;
 
-template <typename Allocator, typename T, typename = void>
-struct allocator_rebind_type {
-    using type = typename rebind<Allocator, T>::type;
-};
+    template <typename Alloc, typename = void>
+    struct allocator_prop_move {
+        using type = std::false_type;
+    };
+    template <typename Alloc>
+    struct allocator_prop_move<
+        Alloc,
+        std::void_t<typename Alloc::propagate_on_container_move_assignment>> {
+        using type = typename Alloc::propagate_on_container_move_assignment;
+    };
+    template <typename Alloc>
+    using allocator_prop_move_t = typename allocator_prop_move<Alloc>::type;
 
-template <typename Allocator, typename T>
-struct allocator_rebind_type<Allocator, T, std::void_t<
-    typename Allocator::template rebind<T>::other
->> {
-    using type = typename Allocator::template rebind<T>::other;
-};
+    template <typename Alloc, typename = void>
+    struct allocator_prop_swap {
+        using type = std::false_type;
+    };
+    template <typename Alloc>
+    struct allocator_prop_swap<
+        Alloc, std::void_t<typename Alloc::propagate_on_container_swap>> {
+        using type = typename Alloc::propagate_on_container_swap;
+    };
+    template <typename Alloc>
+    using allocator_prop_swap_t = typename allocator_prop_swap<Alloc>::type;
+
+    template <typename Alloc, typename = void>
+    struct is_always_equal {
+        using type = std::false_type;
+    };
+    template <typename Alloc>
+    struct is_always_equal<Alloc,
+                           std::void_t<typename Alloc::is_always_equal>> {
+        using type = typename Alloc::is_always_equal;
+    };
+    template <typename Alloc>
+    using is_always_equal_t = typename is_always_equal<Alloc>::type;
+
+    template <typename Alloc, typename = void>
+    struct allocator_select_on_copy {
+        static constexpr Alloc get(const Alloc& alloc) { return alloc; }
+    };
+
+    template <typename Alloc>
+    struct allocator_select_on_copy<
+        Alloc,
+        std::enable_if_t<std::is_same_v<
+            void,
+            std::void_t<
+                decltype(std::declval<Alloc>()
+                             .select_on_container_copy_construction())>>>> {
+        static constexpr Alloc get(const Alloc& alloc) {
+            return alloc.select_on_container_copy_construction();
+        }
+    };
+
+    template <typename Allocator, typename T, typename = void>
+    struct allocator_rebind_type {
+        using type = typename rebind<Allocator, T>::type;
+    };
+
+    template <typename Allocator, typename T>
+    struct allocator_rebind_type<
+        Allocator, T,
+        std::void_t<typename Allocator::template rebind<T>::other>> {
+        using type = typename Allocator::template rebind<T>::other;
+    };
 
 } // namespace __helpers
 
@@ -289,29 +307,30 @@ struct allocator {
     constexpr ~allocator() = default;
 
     // throws std::bad_alloc
-    [[nodiscard]] constexpr T* allocate(std::size_t n)
-    { return static_cast<T*>(::operator new(n * sizeof(T))); }
+    [[nodiscard]] constexpr T* allocate(std::size_t n) {
+        return static_cast<T*>(::operator new(n * sizeof(T)));
+    }
 
     // TODO: check allocated size
-    constexpr void deallocate(T* ptr, std::size_t)
-    { ::operator delete(ptr); }
+    constexpr void deallocate(T* ptr, std::size_t) { ::operator delete(ptr); }
 };
 
 template <typename T1, typename T2>
-constexpr bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept
-{ return true; }
+constexpr bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept {
+    return true;
+}
 
 template <typename T, typename... Args>
-constexpr std::enable_if_t<std::is_same_v<T*,
-    decltype(::new(std::declval<void*>()) T(std::declval<Args>()...))> , T*>
-construct_at(T* p, Args&&... args)
-{
+constexpr std::enable_if_t<
+    std::is_same_v<T*, decltype(::new(std::declval<void*>())
+                                    T(std::declval<Args>()...))>,
+    T*>
+construct_at(T* p, Args&&... args) {
     return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
 }
 
 template <typename T>
-constexpr void destroy_at(T* p)
-{
+constexpr void destroy_at(T* p) {
     // TODO: destroy array
     p->~T();
 }
@@ -320,115 +339,123 @@ template <typename Allocator>
 struct allocator_traits {
     using allocator_type = Allocator;
     using value_type = typename Allocator::value_type;
-    using pointer =
-        __helpers::allocator_pointer_t<Allocator>;
+    using pointer = __helpers::allocator_pointer_t<Allocator>;
     using const_pointer =
         __helpers::allocator_const_pointer_t<Allocator, pointer>;
     using void_pointer =
         __helpers::allocator_void_pointer_t<Allocator, pointer>;
     using const_void_pointer =
         __helpers::allocator_const_void_pointer_t<Allocator, pointer>;
-    using difference_type =
-        __helpers::allocator_difference_type_t<Allocator>;
-    using size_type =
-        __helpers::allocator_size_type_t<Allocator>;
+    using difference_type = __helpers::allocator_difference_type_t<Allocator>;
+    using size_type = __helpers::allocator_size_type_t<Allocator>;
     using propagate_on_container_copy_assignment =
         __helpers::allocator_prop_copy_t<Allocator>;
     using propagate_on_container_move_assignment =
         __helpers::allocator_prop_move_t<Allocator>;
     using propagate_on_container_swap =
         __helpers::allocator_prop_swap_t<Allocator>;
-    using is_always_equal =
-        __helpers::is_always_equal_t<Allocator>;
+    using is_always_equal = __helpers::is_always_equal_t<Allocator>;
 
     template <typename T>
     using rebind_alloc =
         typename __helpers::allocator_rebind_type<Allocator, T>::type;
 
-    [[nodiscard]] static constexpr pointer allocate(Allocator& alloc, size_type n)
-    { return alloc.allocate(n); }
-    static constexpr void deallocate(Allocator& alloc, pointer p, size_type n)
-    { return alloc.deallocate(p, n); }
+    [[nodiscard]] static constexpr pointer allocate(Allocator& alloc,
+                                                    size_type n) {
+        return alloc.allocate(n);
+    }
+    static constexpr void deallocate(Allocator& alloc, pointer p, size_type n) {
+        return alloc.deallocate(p, n);
+    }
     template <typename T, typename... Args>
-    static constexpr void construct(Allocator&, T* p, Args&&... args)
-    { std::construct_at(p, std::forward<Args>(args)...); }
+    static constexpr void construct(Allocator&, T* p, Args&&... args) {
+        std::construct_at(p, std::forward<Args>(args)...);
+    }
     template <typename T>
-    static constexpr void destroy(Allocator&, T* p)
-    { std::destroy_at(p); }
+    static constexpr void destroy(Allocator&, T* p) {
+        std::destroy_at(p);
+    }
 
-    static constexpr Allocator
-        select_on_container_copy_construction(const Allocator& alloc)
-    { return __helpers::allocator_select_on_copy<Allocator>::get(alloc); }
+    static constexpr Allocator select_on_container_copy_construction(
+        const Allocator& alloc) {
+        return __helpers::allocator_select_on_copy<Allocator>::get(alloc);
+    }
+};
+
+template <typename T>
+struct default_delete {
+    __GBLIBCPP_CONSTEXPR default_delete() noexcept = default;
+
+    template <typename U,
+              std::enable_if_t<std::is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR default_delete(const default_delete<U>&) noexcept {}
+
+    __GBLIBCPP_CONSTEXPR void operator()(T* p) const { delete p; }
 };
 
 // TODO: weak_ptr
 template <typename T>
 class shared_ptr {
-public:
+   public:
     using element_type = std::remove_extent_t<T>;
     using pointer = element_type*; // TODO: pointer_traits
     using const_pointer = const element_type*;
     using reference = element_type&;
     using const_reference = const element_type&;
 
-private:
+   private:
     struct control_block_base {
         std::size_t ref_count;
         std::size_t weak_count;
         pointer ptr;
 
         constexpr control_block_base(std::size_t ref_count,
-            std::size_t weak_count, pointer ptr)
-            : ref_count(ref_count), weak_count(weak_count), ptr(ptr) { }
+                                     std::size_t weak_count, pointer ptr)
+            : ref_count(ref_count), weak_count(weak_count), ptr(ptr) {}
 
         virtual constexpr ~control_block_base() = default;
         virtual constexpr void do_delete() = 0;
+
+        // template <typename U, std::enable_if_t<std::is_convertible_v<T*, U*>,
+        // bool> = true> constexpr operator typename
+        // shared_ptr<U>::control_block_base*() const
+        // {
+        //     return this;
+        // }
     };
 
     template <typename Deleter>
-    struct control_block : public virtual control_block_base {
-        Deleter deleter;
-        virtual constexpr ~control_block() = default;
+    struct control_block : public virtual control_block_base, private Deleter {
+        using Base = control_block_base;
 
-        template <typename UDeleter>
-        constexpr control_block(std::size_t ref_count,
-            std::size_t weak_count, pointer ptr, UDeleter&& deleter)
-            : control_block_base { ref_count, weak_count, ptr }
-            , deleter(std::forward<UDeleter>(deleter)) { }
-
-        virtual constexpr void do_delete() override
-        {
-            if (this->ptr)
-                deleter(this->ptr);
-            this->ptr = nullptr;
-        }
-    };
-
-    struct default_control_block : public virtual control_block_base {
-        virtual constexpr ~default_control_block() = default;
+        virtual constexpr ~control_block() = default;
 
-        constexpr default_control_block(std::size_t ref_count,
-            std::size_t weak_count, pointer ptr)
-            : control_block_base { ref_count, weak_count, ptr } { }
+        constexpr control_block(std::size_t ref_count, std::size_t weak_count,
+                                pointer ptr)
+            : control_block_base{ref_count, weak_count, ptr}, Deleter{} {}
 
-        virtual constexpr void do_delete() override
-        {
-            if (this->ptr)
-                delete this->ptr;
-            this->ptr = nullptr;
+        template <typename UDeleter>
+        constexpr control_block(std::size_t ref_count, std::size_t weak_count,
+                                pointer ptr, UDeleter&& deleter)
+            : control_block_base{ref_count, weak_count, ptr}
+            , Deleter(std::forward<UDeleter>(deleter)) {}
+
+        virtual constexpr void do_delete() override {
+            if (this->Base::ptr)
+                this->Deleter::operator()(this->Base::ptr);
+            this->Base::ptr = nullptr;
         }
     };
 
-    control_block_base* cb { };
+    control_block_base* cb{};
+    pointer ptr{};
 
-    void inc_ref()
-    {
+    void inc_ref() {
         if (cb)
             ++cb->ref_count; // TODO: lock and atomic
     }
 
-    void dec_ref()
-    {
+    void dec_ref() {
         if (cb && --cb->ref_count == 0) {
             cb->do_delete();
             if (cb->weak_count == 0)
@@ -436,130 +463,112 @@ private:
         }
     }
 
-private:
-    template <typename Deleter>
-    using rebind_allocator = typename std::allocator_traits<Deleter>::template
-        rebind_alloc<control_block<Deleter>>;
+   private:
+    template <typename Allocator, typename Deleter>
+    using rebound_allocator = typename std::allocator_traits<
+        Allocator>::template rebind_alloc<control_block<Deleter>>;
+
+    template <typename Allocator, typename Deleter>
+    using rebound_traits =
+        typename std::allocator_traits<rebound_allocator<Allocator, Deleter>>;
 
     template <typename U>
     friend class shared_ptr;
 
-public:
-    constexpr shared_ptr() noexcept = default;
-    constexpr shared_ptr(std::nullptr_t) noexcept : cb { } { }
+   public:
+    __GBLIBCPP_CONSTEXPR shared_ptr() noexcept = default;
+    __GBLIBCPP_CONSTEXPR shared_ptr(std::nullptr_t) noexcept : shared_ptr{} {}
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    explicit shared_ptr(U* ptr) // TODO: array type
-        : cb(new default_control_block { 1, 0, ptr }) { }
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p) // TODO: array type
+        : cb(new control_block<default_delete<T>>{1, 0, p}), ptr(p) {}
 
-    template <typename U, typename Deleter>
-    __GBLIBCPP_CONSTEXPR
-    explicit shared_ptr(U* ptr, Deleter d)
-        : cb(new control_block<Deleter> { 1, 0, ptr, d }) { }
+    template <typename U, typename Deleter,
+              enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d)
+        : cb(new control_block<Deleter>{1, 0, p, d}), ptr(p) {}
 
     template <typename Deleter>
-    __GBLIBCPP_CONSTEXPR
-    explicit shared_ptr(std::nullptr_t, Deleter d)
-        : cb(new control_block<Deleter> { 1, 0, nullptr, d }) { }
-
-    // TODO: what the fuck
-    // template <typename U, typename Deleter, typename Allocator>
-    // __GBLIBCPP_CONSTEXPR
-    // explicit shared_ptr(U* ptr, Deleter d, Allocator alloc)
-    // {
-    //     cb = std::allocator_traits<
-    //         rebind_allocator<Deleter>>::allocate(alloc, 1);
-
-    //     std::allocator_traits<
-    //         rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, ptr, d);
-    // }
-
-    // template <typename Deleter, typename Allocator>
-    // __GBLIBCPP_CONSTEXPR
-    // explicit shared_ptr(std::nullptr_t, Deleter d, Allocator alloc)
-    // {
-    //     cb = std::allocator_traits<
-    //         rebind_allocator<Deleter>>::allocate(alloc, 1);
-
-    //     std::allocator_traits<
-    //         rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, nullptr, d);
-    // }
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d)
+        : cb(new control_block<Deleter>{1, 0, nullptr, d}) {}
 
-    __GBLIBCPP_CONSTEXPR
-    shared_ptr(const shared_ptr& other) noexcept
-        : cb(other.cb) { inc_ref(); }
+    template <typename U, typename Deleter, typename Alloc,
+              enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d, Alloc alloc) {
+        cb = rebound_traits<Alloc, Deleter>::allocate(alloc, 1);
+        rebound_traits<Alloc, Deleter>::construct(alloc, cb, 1, 0, p, d);
+
+        ptr = p;
+    }
+
+    template <typename Deleter, typename Alloc>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d,
+                                             Alloc alloc) {
+        cb = rebound_traits<Alloc, Deleter>::allocate(alloc, 1);
+        rebound_traits<Alloc, Deleter>::construct(alloc, cb, 1, 0, nullptr, d);
+    }
 
-    template <typename U>
     __GBLIBCPP_CONSTEXPR
-    shared_ptr(const shared_ptr<U>& other) noexcept
-        : cb(other.cb) { inc_ref(); }
+    shared_ptr(const shared_ptr& other) noexcept
+        : cb(other.cb), ptr(other.ptr) {
+        inc_ref();
+    }
 
     __GBLIBCPP_CONSTEXPR
     shared_ptr(shared_ptr&& other) noexcept
-        : cb(std::exchange(other.cb, nullptr)) { }
+        : cb(std::exchange(other.cb, nullptr))
+        , ptr(std::exchange(other.ptr, nullptr)) {}
+
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR shared_ptr(const shared_ptr<U>& other) noexcept
+        : cb((control_block_base*)other.cb), ptr((T*)other.ptr) {
+        inc_ref();
+    }
+
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR shared_ptr(shared_ptr<U>&& other) noexcept
+        : cb((control_block_base*)std::exchange(other.cb, nullptr))
+        , ptr((T*)std::exchange(other.ptr, nullptr)) {}
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    shared_ptr(shared_ptr<U>&& other) noexcept
-        : cb(std::exchange(other.cb, nullptr)) { }
-    
     // TODO: weak_ptr and unique_ptr
 
     __GBLIBCPP_CONSTEXPR
-    ~shared_ptr() { dec_ref(); }
+    ~shared_ptr() {
+        dec_ref();
+        cb = nullptr;
+        ptr = nullptr;
+    }
 
     __GBLIBCPP_CONSTEXPR
-    shared_ptr& operator=(const shared_ptr& other) noexcept
-    {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = other.cb;
-            inc_ref();
-        }
+    shared_ptr& operator=(const shared_ptr& other) noexcept {
+        shared_ptr{other}.swap(*this);
         return *this;
     }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    shared_ptr& operator=(const shared_ptr<U>& other) noexcept
-    {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = other.cb;
-            inc_ref();
-        }
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR shared_ptr& operator=(
+        const shared_ptr<U>& other) noexcept {
+        shared_ptr{other}.swap(*this);
         return *this;
     }
 
     __GBLIBCPP_CONSTEXPR
-    shared_ptr& operator=(shared_ptr&& other) noexcept
-    {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = std::exchange(other.cb, nullptr);
-        }
+    shared_ptr& operator=(shared_ptr&& other) noexcept {
+        shared_ptr{move(other)}.swap(*this);
         return *this;
     }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    shared_ptr& operator=(shared_ptr<U>&& other) noexcept
-    {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = std::exchange(other.cb, nullptr);
-        }
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR shared_ptr& operator=(shared_ptr<U>&& other) noexcept {
+        shared_ptr{move(other)}.swap(*this);
         return *this;
     }
 
     __GBLIBCPP_CONSTEXPR
-    element_type* get() const noexcept
-    { return cb ? cb->ptr : nullptr; }
+    element_type* get() const noexcept { return cb ? ptr : nullptr; }
 
     __GBLIBCPP_CONSTEXPR
-    explicit operator bool() const noexcept
-    { return get(); }
+    explicit operator bool() const noexcept { return get(); }
 
     __GBLIBCPP_CONSTEXPR
     T& operator*() const noexcept { return *get(); }
@@ -572,45 +581,159 @@ public:
     long use_count() const noexcept { return cb ? cb->ref_count : 0; }
 
     __GBLIBCPP_CONSTEXPR
-    bool owner_before(const shared_ptr& other) const noexcept
-    { return cb < other.cb; }
+    bool owner_before(const shared_ptr& other) const noexcept {
+        return cb < other.cb;
+    }
 
     __GBLIBCPP_CONSTEXPR
-    void swap(shared_ptr& other) noexcept { std::swap(cb->ptr, other.cb->ptr); }
+    void swap(shared_ptr& other) noexcept {
+        std::swap(cb, other.cb);
+        std::swap(ptr, other.ptr);
+    }
 
     __GBLIBCPP_CONSTEXPR
-    void reset() noexcept { dec_ref(); cb = nullptr; }
+    void reset() noexcept { shared_ptr{}.swap(*this); }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    void reset(U* ptr) noexcept
-    { dec_ref(); cb = new default_control_block { 1, 0, ptr }; }
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR void reset(U* p) noexcept {
+        shared_ptr{p}.swap(*this);
+    }
 
-    template <typename U, typename Deleter>
-    __GBLIBCPP_CONSTEXPR
-    void reset(U* ptr, Deleter d) noexcept
-    { dec_ref(); cb = new control_block<Deleter> { 1, 0, ptr, d }; }
-
-    // TODO: what the fuck
-    // template <typename U, typename Deleter, typename Allocator>
-    // __GBLIBCPP_CONSTEXPR
-    // void reset(U* ptr, Deleter d, Allocator alloc)
-    // {
-    //     dec_ref();
-    //     cb = std::allocator_traits<
-    //         rebind_allocator<Deleter>>::allocate(alloc, 1);
-
-    //     std::allocator_traits<
-    //         rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, ptr, d);
-    // }
+    template <typename U, typename Deleter,
+              enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d) noexcept {
+        shared_ptr{p, d}.swap(*this);
+    }
+
+    template <typename U, typename Deleter, typename Allocator,
+              enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d, Allocator alloc) {
+        shared_ptr{p, d, alloc}.swap(*this);
+    }
+};
+
+template <typename T, typename Deleter = std::default_delete<T>>
+class unique_ptr {
+   public:
+    using element_type = T;
+    using deleter_type = Deleter;
+    using pointer = element_type*;
+
+    template <typename U, typename UDeleter>
+    friend class unique_ptr;
+
+   private:
+    impl::compressed_pair<pointer, deleter_type> data;
+
+   public:
+    __GBLIBCPP_CONSTEXPR unique_ptr() noexcept
+        : data{impl::default_construct_t{}} {}
+    __GBLIBCPP_CONSTEXPR unique_ptr(std::nullptr_t) noexcept : unique_ptr{} {}
+    __GBLIBCPP_CONSTEXPR unique_ptr(pointer p) noexcept
+        : data{p, deleter_type{}} {}
+    __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, const deleter_type& d) noexcept
+        : data{p, d} {}
+    __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, deleter_type&& d) noexcept
+        : data{p, std::move(d)} {}
+    __GBLIBCPP_CONSTEXPR unique_ptr(const unique_ptr&) = delete;
+
+    __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr&& other) noexcept
+        : data{std::exchange(other.data.first(), nullptr),
+               std::move(other.data.second())} {}
+
+    template <
+        typename U, typename E,
+        std::enable_if_t<!std::is_array_v<U> && std::is_convertible_v<U*, T*> &&
+                             std::is_convertible_v<E, Deleter>,
+                         bool> = true>
+    __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr<U, E>&& other) noexcept
+        : data{std::exchange(other.data.first(), nullptr),
+               std::move(other.data.second())} {}
+
+    __GBLIBCPP_CONSTEXPR ~unique_ptr() { reset(); }
+
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(const unique_ptr&) = delete;
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(std::nullptr_t) noexcept {
+        reset();
+        return *this;
+    }
+
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(unique_ptr&& other) noexcept {
+        reset(other.release());
+        get_deleter() = std::move(other.get_deleter());
+        return *this;
+    }
+
+    template <
+        typename U, typename E,
+        std::enable_if_t<!std::is_array_v<U> && std::is_convertible_v<U*, T*> &&
+                             std::is_assignable_v<Deleter&, E&&>,
+                         bool> = true>
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(
+        unique_ptr<U, E>&& other) noexcept {
+        reset(other.release());
+        get_deleter() = std::move(other.get_deleter());
+        return *this;
+    }
+
+    __GBLIBCPP_CONSTEXPR void swap(unique_ptr& other) noexcept {
+        std::swap(data, other.data);
+    }
+
+    __GBLIBCPP_CONSTEXPR pointer get() const noexcept { return data.first(); }
+    __GBLIBCPP_CONSTEXPR deleter_type& get_deleter() noexcept {
+        return data.second();
+    }
+    __GBLIBCPP_CONSTEXPR const deleter_type& get_deleter() const noexcept {
+        return data.second();
+    }
+
+    __GBLIBCPP_CONSTEXPR pointer release() noexcept {
+        pointer ret = get();
+        data.first() = nullptr;
+        return ret;
+    }
+
+    __GBLIBCPP_CONSTEXPR void reset(pointer p = pointer{}) noexcept {
+        pointer old = release();
+        data.first() = p;
+        if (old)
+            get_deleter()(old);
+    }
+
+    __GBLIBCPP_CONSTEXPR explicit operator bool() const noexcept {
+        return get();
+    }
+    __GBLIBCPP_CONSTEXPR pointer operator->() const noexcept { return get(); }
+
+    __GBLIBCPP_CONSTEXPR std::add_lvalue_reference_t<T> operator*() const
+        noexcept(noexcept(*std::declval<pointer>())) {
+        return *get();
+    }
 };
 
 // TODO: use only one allocation
-// template <typename T, typename... Args>
-// std::shared_ptr<T> make_shared(Args&&... args)
-// {
-//     return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
-// }
+template <typename T, typename... Args>
+std::shared_ptr<T> make_shared(Args&&... args) {
+    return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+template <typename T, typename... Args>
+__GBLIBCPP_CONSTEXPR std::unique_ptr<T> make_unique(Args&&... args) {
+    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+template <typename T>
+__GBLIBCPP_CONSTEXPR void swap(std::shared_ptr<T>& lhs,
+                               std::shared_ptr<T>& rhs) noexcept {
+    lhs.swap(rhs);
+}
+
+template <typename T, typename D>
+__GBLIBCPP_CONSTEXPR void swap(std::unique_ptr<T, D>& lhs,
+                               std::unique_ptr<T, D>& rhs) noexcept {
+    lhs.swap(rhs);
+}
 
 } // namespace std
 

+ 1 - 1
gblibstdc++/include/queue

@@ -48,7 +48,7 @@ public:
     __GBLIBCPP_CONSTEXPR
     explicit priority_queue(const Compare& comp)
         : priority_queue(comp, Container()) {}
-    
+
     template <typename InputIter>
     __GBLIBCPP_CONSTEXPR
     priority_queue(InputIter first, InputIter last,

+ 4 - 4
gblibstdc++/include/set

@@ -49,7 +49,7 @@ public:
     set(const Compare& comp,
         const Allocator& alloc = Allocator())
         : tree(comp, alloc) {}
-    
+
     explicit __GBLIBCPP_CONSTEXPR
     set(const Allocator& alloc)
         : set(Compare(), alloc) {}
@@ -91,15 +91,15 @@ public:
         const Allocator& alloc = Allocator())
         : set(comp, alloc)
     { insert(ilist.begin(), ilist.end()); }
-    
+
     __GBLIBCPP_CONSTEXPR
     set(std::initializer_list<Key> ilist,
         const Allocator& alloc)
         : set(ilist, Compare(), alloc) {}
-    
+
     __GBLIBCPP_CONSTEXPR
     ~set() { clear(); }
-    
+
     __GBLIBCPP_CONSTEXPR
     set& operator=(const set& other) = default;
     __GBLIBCPP_CONSTEXPR

+ 543 - 0
gblibstdc++/include/string

@@ -0,0 +1,543 @@
+#ifndef __GBLIBCPP_STRING__
+#define __GBLIBCPP_STRING__
+
+#include <bits/compressed_pair>
+#include <bits/iter_ops>
+
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <initializer_list>
+#include <cstddef>
+
+#include <string.h>
+
+namespace std {
+
+template <typename T>
+class char_traits;
+
+template <>
+class char_traits<char>
+{
+public:
+    static std::size_t length(const char* str) { return strlen(str); }
+
+    static int compare(const char* s1, const char* s2, std::size_t cnt)
+    {
+        return strncmp(s1, s2, cnt);
+    }
+};
+
+template <typename Char,
+         typename Traits = std::char_traits<Char>,
+         typename Allocator = std::allocator<Char>>
+class basic_string {
+public:
+    using traits_type = Traits;
+    using value_type = Char;
+    using allocator_type = Allocator;
+    using size_type = typename std::allocator_traits<Allocator>::size_type;
+    using difference_type = typename std::allocator_traits<Allocator>::difference_type;
+    using reference = value_type&;
+    using const_reference = const value_type&;
+    using pointer = typename std::allocator_traits<Allocator>::pointer;
+    using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
+
+    template <bool Const>
+    class _iterator {
+    public:
+        // TODO:
+        // using iterator_category = std::random_access_iterator_tag;
+        using _reference = std::conditional_t<Const, const_reference, reference>;
+
+    private:
+        pointer m_ptr;
+
+    public:
+        constexpr _iterator(void) noexcept : m_ptr() {}
+        constexpr explicit _iterator(pointer ptr) noexcept
+            : m_ptr(ptr) {}
+        constexpr _iterator(const _iterator& other) noexcept = default;
+        constexpr _iterator(_iterator&& other) noexcept = default;
+        constexpr _iterator& operator=(const _iterator& other) noexcept = default;
+        constexpr _iterator& operator=(_iterator&& other) noexcept = default;
+        constexpr bool operator==(const _iterator& other) const noexcept = default;
+
+        constexpr _reference operator*() const noexcept { return *m_ptr; }
+        constexpr pointer operator&() const noexcept
+        { return std::addressof(this->operator*()); }
+        constexpr pointer operator->() const noexcept
+        { return this->operator&(); }
+        constexpr _iterator& operator++() noexcept
+        { ++m_ptr; return *this; }
+        constexpr _iterator operator++(int) noexcept
+        { _iterator ret(m_ptr); (void)this->operator++(); return ret; }
+        constexpr _iterator& operator--(void) noexcept
+        { --m_ptr; return *this; }
+        constexpr _iterator operator--(int) noexcept
+        { _iterator ret(m_ptr); (void)this->operator--(); return ret; }
+        constexpr _iterator& operator+=(difference_type n) noexcept
+        { m_ptr += n; return *this; }
+        constexpr _iterator& operator-=(difference_type n) noexcept
+        { m_ptr -= n; return *this; }
+        constexpr _iterator operator+(difference_type n) const noexcept
+        { return _iterator { m_ptr + n }; }
+        constexpr _iterator operator-(difference_type n) const noexcept
+        { return _iterator { m_ptr - n }; }
+        constexpr difference_type operator-(const _iterator& other) const noexcept
+        { return m_ptr - other.m_ptr; }
+        constexpr _reference operator[](difference_type n) const noexcept
+        { return m_ptr[n]; }
+        constexpr operator bool() { return m_ptr; }
+        constexpr operator _iterator<true>() { return _iterator<true> { m_ptr }; }
+        constexpr operator _iterator<false>() { return _iterator<false> { m_ptr }; }
+        constexpr operator pointer() { return m_ptr; }
+    };
+
+private:
+    using alloc_traits = std::allocator_traits<Allocator>;
+
+public:
+    using iterator = _iterator<false>;
+    using const_iterator = _iterator<true>;
+
+private:
+    static constexpr std::size_t STATIC_SIZE = 32;
+    static constexpr std::size_t STATIC_COUNT =
+        STATIC_SIZE / sizeof(Char) - 2;
+
+    struct string_data_type { union {
+        std::byte __data[STATIC_SIZE];
+
+        struct {
+            union {
+                Char __data;
+                unsigned char n;
+            } m_size;
+            Char str[STATIC_COUNT];
+            Char end;
+        } stackdata;
+
+        struct {
+            std::size_t m_size;
+            std::size_t m_capacity;
+            Char* m_ptr;
+        } heapdata;
+
+    } in; };
+    impl::compressed_pair<string_data_type, Allocator> m_data;
+
+    constexpr Allocator& _alloc() noexcept { return m_data.second(); }
+    constexpr const Allocator& _alloc() const noexcept { return m_data.second(); }
+
+    constexpr bool _stack_data() const
+    {
+        return m_data.first().in.stackdata.end == 0;
+    }
+
+    constexpr bool _stack_data(bool val)
+    {
+        return (m_data.first().in.stackdata.end = !val), val;
+    }
+
+    constexpr void _release()
+    {
+        if (_stack_data()) {
+            _size(0);
+            return;
+        }
+
+        alloc_traits::deallocate(m_data.second(), data(), capacity()+1);
+
+        _stack_data(true);
+        _size(0);
+        _data()[0] = 0;
+    }
+
+    constexpr void _reserve(std::size_t cnt)
+    {
+        std::size_t cursize = size();
+        Char* newdata = alloc_traits::allocate(_alloc(), cnt+1);
+
+        memcpy(newdata, data(), size());
+        newdata[cursize] = 0;
+
+        if (_stack_data()) {
+            _stack_data(false);
+            _size(cursize);
+        }
+        else {
+            alloc_traits::deallocate(_alloc(), data(), capacity()+1);
+        }
+
+        _capacity(cnt);
+        _data(newdata);
+    }
+
+    constexpr std::size_t _size() const
+    {
+        if (_stack_data())
+            return m_data.first().in.stackdata.m_size.n;
+        else
+            return m_data.first().in.heapdata.m_size;
+    }
+
+    constexpr std::size_t _size(std::size_t val)
+    {
+        if (_stack_data())
+            return m_data.first().in.stackdata.m_size.n = (Char)val;
+        else
+            return m_data.first().in.heapdata.m_size = val;
+    }
+
+    constexpr std::size_t _capacity() const
+    {
+        if (_stack_data())
+            return STATIC_COUNT;
+        else
+            return m_data.first().in.heapdata.m_capacity;
+    }
+
+    constexpr std::size_t _capacity(std::size_t val)
+    {
+        if (_stack_data())
+            return STATIC_COUNT;
+        else
+            return m_data.first().in.heapdata.m_capacity = val;
+    }
+
+    constexpr const Char* _data() const
+    {
+        if (_stack_data())
+            return m_data.first().in.stackdata.str;
+        else
+            return m_data.first().in.heapdata.m_ptr;
+    }
+
+    constexpr Char* _data()
+    {
+        if (_stack_data())
+            return m_data.first().in.stackdata.str;
+        else
+            return m_data.first().in.heapdata.m_ptr;
+    }
+
+    constexpr Char* _data(Char* val)
+    {
+        if (_stack_data())
+            return m_data.first().in.stackdata.str;
+        else
+            return m_data.first().in.heapdata.m_ptr = val;
+    }
+
+public:
+    constexpr basic_string() noexcept(noexcept(Allocator()))
+        : basic_string{Allocator{}} { }
+
+    constexpr explicit basic_string(const Allocator& alloc) noexcept
+        : m_data{{}, alloc} { }
+
+    constexpr basic_string(const basic_string& other, const Allocator& alloc)
+        : basic_string{alloc}
+    {
+        append(other.c_str(), other.size());
+    }
+
+    constexpr basic_string(const basic_string& other)
+        : basic_string{other, alloc_traits::
+            select_on_container_copy_construction(other._alloc())} { }
+
+    constexpr basic_string(basic_string&& other) noexcept
+        : m_data{other.m_data.first(), std::move(other._alloc())}
+    {
+        other._stack_data(true);
+        other._size(0);
+        other._data()[0] = 0;
+    }
+
+    constexpr basic_string(basic_string&& other, const Allocator& alloc)
+        : basic_string{alloc}
+    {
+        if (alloc == other._alloc()) {
+            m_data.first() = other.m_data.first();
+            other._stack_data(true);
+            other._size(0);
+            other._data()[0] = 0;
+        }
+        else {
+            append(other.c_str(), other.size());
+        }
+    }
+
+    constexpr basic_string(const basic_string& other, size_type pos,
+            const Allocator& alloc = Allocator{})
+        : basic_string{other.c_str() + pos, alloc} { }
+
+    // constexpr basic_string(std::initializer_list<Char> ilist,
+    //         const Allocator& alloc = Allocator{})
+    //     : basic_string {alloc}
+    // {
+    //     assign(ilist.begin(), ilist.end());
+    // }
+
+    constexpr basic_string(const Char* str, size_type count,
+            const Allocator& alloc = Allocator{})
+        : basic_string{alloc}
+    {
+        assign(str, count);
+    }
+
+    constexpr basic_string(const Char* str, const Allocator& alloc = Allocator{})
+        : basic_string{str, traits_type::length(str), alloc} { }
+
+    constexpr ~basic_string()
+    {
+        _release();
+    }
+
+    constexpr basic_string& operator=(const Char* str)
+    {
+        return assign(str);
+    }
+
+    constexpr basic_string& operator=(const basic_string& other)
+    {
+        return assign(other.c_str(), other.size());
+    }
+
+    constexpr basic_string& operator=(basic_string&& other)
+    {
+        if constexpr (alloc_traits::
+                propagate_on_container_move_assignment::value) {
+            _release();
+            _alloc() = std::move(other._alloc());
+        }
+        else {
+            if (_alloc() != other._alloc()) {
+                assign(other.c_str(), other.size());
+                return *this;
+            }
+            _release();
+        }
+
+        m_data.first() = other.m_data.first();
+        other._stack_data(true);
+        other._size(0);
+        other._data()[0] = 0;
+
+        return *this;
+    }
+
+    constexpr basic_string& operator=(Char ch)
+    {
+        return assign(1, ch);
+    }
+
+    // constexpr basic_string& operator=(std::initializer_list<Char> init)
+    // {
+    //     assign(init.begin(), init.end());
+    //     return *this;
+    // }
+
+    constexpr basic_string& append(std::size_t len, Char ch)
+    {
+        std::size_t cursize = size();
+        std::size_t newsize = cursize + len;
+
+        if (newsize > capacity())
+            _reserve(std::max(capacity() * 2, newsize));
+
+        auto* pdata = data();
+        for (std::size_t i = cursize; i < newsize; ++i)
+            pdata[i] = ch;
+        pdata[newsize] = 0;
+
+        _size(newsize);
+
+        return *this;
+    }
+
+    constexpr basic_string& append(const Char* str, std::size_t count)
+    {
+        std::size_t cursize = size();
+        std::size_t newsize = cursize + count;
+
+        if (newsize > capacity())
+            _reserve(std::max(capacity() * 2, newsize));
+
+        memcpy(data() + cursize, str, count);
+        data()[newsize] = 0;
+
+        _size(newsize);
+
+        return *this;
+    }
+
+    constexpr basic_string& append(const Char* str)
+    {
+        return append(str, traits_type::length(str));
+    }
+
+    constexpr basic_string& assign(size_type n, Char ch)
+    {
+        clear();
+        return append(n, ch);
+    }
+
+    constexpr basic_string& assign(const Char* str, size_type count)
+    {
+        clear();
+        return append(str, count);
+    }
+
+    constexpr basic_string& assign(const Char* str)
+    {
+        return assign(str, traits_type::length(str));
+    }
+
+    // TODO: check whether InputIter satisfies LegacyInputIterator
+    // template <typename InputIter>
+    // constexpr basic_string& assign(InputIter first, InputIter last)
+    // {
+    //     clear();
+    //     insert(cbegin(), first, last);
+    //     return *this;
+    // }
+    // constexpr basic_string& assign(std::initializer_list<T> init)
+    // {
+    //     clear();
+    //     insert(cbegin(), init.begin(), init.end());
+    //     return *this;
+    // }
+
+    constexpr basic_string& operator+=(Char ch)
+    {
+        return append(1, ch);
+    }
+
+    constexpr basic_string& operator+=(const Char* str)
+    {
+        return append(str);
+    }
+
+    constexpr basic_string& operator+=(const basic_string& str)
+    {
+        return append(str.c_str(), str.size());
+    }
+
+    constexpr bool empty() const noexcept
+    { return size() == 0; }
+    constexpr size_type size() const noexcept
+    { return _size(); }
+    constexpr size_type capacity() const noexcept
+    { return _capacity(); }
+
+    constexpr Char* data() noexcept { return _data(); }
+    constexpr const Char* data() const noexcept { return _data(); }
+    constexpr const Char* c_str() const noexcept { return data(); }
+
+    constexpr reference operator[](size_type pos)
+    { return data()[pos]; }
+    constexpr const_reference operator[](size_type pos) const
+    { return data()[pos]; }
+
+    // constexpr reference at(size_type pos)
+    // {
+    //     // TODO: exceptions
+    //     // if (pos >= size())
+    //     //     throw std::out_of_range("basic_string::at");
+    //     return operator[](pos);
+    // }
+    // constexpr const_reference at(size_type pos) const
+    // {
+    //     // TODO: exceptions
+    //     // if (pos >= size())
+    //     //     throw std::out_of_range("basic_string::at");
+    //     return operator[](pos);
+    // }
+
+    constexpr reference front() noexcept
+    { return operator[](0); }
+    constexpr const_reference front() const noexcept
+    { return operator[](0); }
+    constexpr reference back() noexcept
+    { return operator[](size() - 1); }
+    constexpr const_reference back() const noexcept
+    { return operator[](size() - 1); }
+
+    // TODO: std::reverse_iterator
+    constexpr iterator begin() noexcept
+    { return iterator { data() }; }
+    constexpr const_iterator begin() const noexcept
+    { return const_iterator { data() }; }
+    constexpr const_iterator cbegin() const noexcept
+    { return const_iterator { data() }; }
+    constexpr iterator end() noexcept
+    { return iterator { data() + size() }; }
+    constexpr const_iterator end() const noexcept
+    { return const_iterator { data() + size() }; }
+    constexpr const_iterator cend() const noexcept
+    { return const_iterator { data() + size() }; }
+
+    constexpr void clear() noexcept{ _size(0); }
+
+    constexpr void push_back(Char ch) { append(1, ch); }
+    constexpr void pop_back() { erase(cend()-1); }
+
+    constexpr void swap(basic_string& other) noexcept(
+        alloc_traits::propagate_on_container_swap::value
+        || alloc_traits::is_always_equal::value)
+    {
+        if (alloc_traits::propagate_on_container_swap::value)
+            std::swap(_alloc(), other._alloc());
+        std::swap(m_data.first(), other.m_data.first());
+    }
+
+    constexpr int compare(const basic_string& str) const noexcept
+    {
+        return traits_type::compare(c_str(), str.c_str(), size()+1);
+    }
+
+    constexpr int compare(const Char* str) const
+    {
+        return traits_type::compare(c_str(), str, size()+1);
+    }
+};
+
+template <typename Char, typename Traits, typename Allocator>
+constexpr bool operator==(
+    const std::basic_string<Char, Traits, Allocator>& lhs,
+    const std::basic_string<Char, Traits, Allocator>& rhs) noexcept
+{
+    return lhs.compare(rhs) == 0;
+}
+
+template <typename Char, typename Traits, typename Allocator>
+constexpr bool operator==(
+    const std::basic_string<Char, Traits, Allocator>& lhs, const Char* rhs)
+{
+    return lhs.compare(rhs) == 0;
+}
+
+template <typename Char, typename Traits, typename Allocator>
+constexpr bool operator<(
+    const std::basic_string<Char, Traits, Allocator>& lhs,
+    const std::basic_string<Char, Traits, Allocator>& rhs) noexcept
+{
+    return lhs.compare(rhs) < 0;
+}
+
+template <typename Char, typename Traits, typename Allocator>
+constexpr void swap(
+    std::basic_string<Char, Traits, Allocator>& lhs,
+    std::basic_string<Char, Traits, Allocator>& rhs) noexcept(noexcept(lhs.swap(rhs)))
+{
+    lhs.swap(rhs);
+}
+
+using string = basic_string<char>;
+
+} // namespace std
+
+#endif

+ 9 - 9
gblibstdc++/include/tuple

@@ -80,7 +80,7 @@ class tuple_impl<0> {
     template <std::size_t> constexpr void _getr(void) const = delete;
 public:
     constexpr tuple_impl() noexcept = default;
-    
+
     constexpr tuple_impl(const tuple_impl& arg) noexcept = default;
     constexpr tuple_impl(tuple_impl&& arg) noexcept = default;
 
@@ -88,7 +88,7 @@ public:
     constexpr tuple_impl(const std::tuple<UTypes...>& other) = delete;
     template <typename... UTypes>
     constexpr tuple_impl(std::tuple<UTypes...>&& other) = delete;
-    
+
     constexpr tuple_impl& operator=(const tuple_impl& other) noexcept = default;
     constexpr tuple_impl& operator=(tuple_impl&& other) noexcept = default;
 };
@@ -157,13 +157,13 @@ class tuple_impl<I, Type, Types...> {
 public:
     constexpr tuple_impl()
         : val(), next() {}
-    
+
     constexpr tuple_impl(const tuple_impl& arg) = default;
     constexpr tuple_impl(tuple_impl&& arg) = default;
 
     constexpr tuple_impl(const Type& val, const Types&... vals)
         : val(val), next(vals...) {}
-    
+
     template <typename UType, typename... UTypes>
     constexpr tuple_impl(UType&& val, UTypes&&... vals)
         : val(std::forward<UType>(val)), next(std::forward<UTypes>(vals)...) {}
@@ -174,7 +174,7 @@ public:
     template <typename... UTypes>
     constexpr tuple_impl(std::tuple<UTypes...>&& other)
         : val(std::get<I>(other)), next(std::move(other)) {}
-    
+
     constexpr tuple_impl& operator=(const tuple_impl& other) = default;
     constexpr tuple_impl& operator=(tuple_impl&& other) = default;
 };
@@ -227,7 +227,7 @@ class tuple_impl<I, Type> {
 public:
     constexpr tuple_impl()
         : val() {}
-    
+
     constexpr tuple_impl(const tuple_impl& arg) = default;
     constexpr tuple_impl(tuple_impl&& arg) = default;
 
@@ -329,7 +329,7 @@ public:
     , bool> = true>
     constexpr tuple(const Types&... args)
         : base(args...) {}
-    
+
     template <typename... UTypes, std::enable_if_t<
         sizeof...(UTypes) == sizeof...(Types)
         && sizeof...(Types) >= 1
@@ -353,14 +353,14 @@ public:
     , bool> = true>
     constexpr tuple(tuple<UTypes...>&& other)
         : base(std::move(other)) {}
-    
+
     template <typename U1, typename U2, std::enable_if_t<
         __helpers::tuple_constraints<Types...>::template
             tuple_pair_constructible<const std::pair<U1, U2>&>::value
     , bool> = true>
     constexpr tuple(const std::pair<U1, U2>& p)
         : base(std::get<0>(p), std::get<1>(p)) {}
-    
+
     template <typename U1, typename U2, std::enable_if_t<
         __helpers::tuple_constraints<Types...>::template
             tuple_pair_constructible<std::pair<U1, U2>&&>::value

+ 1 - 1
gblibstdc++/include/utility

@@ -126,7 +126,7 @@ struct pair {
         second = std::forward<U2>(other.second);
         return *this;
     }
-    
+
     constexpr void swap(pair& other)
     {
         std::swap(first, other.first);

+ 72 - 71
gblibstdc++/include/vector

@@ -2,6 +2,7 @@
 #define __GBLIBCPP_VECTOR__
 
 #include <bits/iter_ops>
+#include <bits/compressed_pair>
 
 #include <functional>
 #include <memory>
@@ -84,49 +85,50 @@ public:
     using const_iterator = _iterator<true>;
 
 private:
-    T* m_data;
+    impl::compressed_pair<T*, allocator_type> m_data;
     size_type m_size;
     size_type m_capacity;
-    allocator_type m_alloc;
 
 private:
+    constexpr allocator_type& _alloc() noexcept { return m_data.second(); }
+    constexpr const allocator_type& _alloc() const noexcept { return m_data.second(); }
+    constexpr T*& _data() noexcept { return m_data.first(); }
+    constexpr T* const& _data() const noexcept { return m_data.first(); }
+
     // assert(n >= m_size)
     constexpr void _reallocate_safe(size_type n)
     {
         T* newptr = nullptr;
         if (n)
-            newptr = alloc_traits::allocate(m_alloc, n);
+            newptr = alloc_traits::allocate(_alloc(), n);
 
         for (size_t i = 0; i < m_size; ++i) {
             if (n)
-                alloc_traits::construct(m_alloc, newptr + i, std::move(m_data[i]));
-            alloc_traits::destroy(m_alloc, m_data + i);
+                alloc_traits::construct(_alloc(), newptr + i, std::move(_data()[i]));
+            alloc_traits::destroy(_alloc(), _data() + i);
         }
 
-        alloc_traits::deallocate(m_alloc, m_data, m_capacity);
-        m_data = newptr;
+        alloc_traits::deallocate(_alloc(), _data(), m_capacity);
+        _data() = newptr;
         m_capacity = n;
     }
 
     // make m_capacity >= n >= m_size
     constexpr void _pre_resize(size_type n)
     {
-        if (n < m_size) {
-            while (n < m_size)
-                pop_back();
-        }
-        else if (n > m_size) {
-            reserve(n);
-        }
+        while (n < m_size)
+            pop_back();
+
+        reserve(n);
     }
 
 public:
     constexpr vector(void)
         noexcept(noexcept(Allocator()))
-        : m_data(), m_size(), m_capacity(), m_alloc() {}
+        : m_data{impl::default_construct_t{}}, m_size(), m_capacity() {}
 
     constexpr explicit vector(const Allocator& alloc) noexcept
-        : m_data(), m_size(), m_capacity(), m_alloc(alloc) {}
+        : m_data{nullptr, alloc}, m_size(), m_capacity() {}
 
     constexpr vector(size_type n, const T& val,
         const Allocator& alloc = Allocator())
@@ -144,23 +146,22 @@ public:
 
     constexpr vector(const vector& other)
         : vector(std::allocator_traits<allocator_type>::
-            select_on_container_copy_construction(other.m_alloc))
+            select_on_container_copy_construction(other._alloc()))
     { insert(cbegin(), other.begin(), other.end()); }
 
     constexpr vector(const vector& other, const Allocator& alloc)
         : vector(alloc) { insert(cbegin(), other.begin(), other.end()); }
 
     constexpr vector(vector&& other) noexcept
-        : m_data(std::exchange(other.m_data, nullptr))
+        : m_data{std::exchange(other._data(), nullptr), std::move(other._alloc())}
         , m_size(std::exchange(other.m_size, 0))
-        , m_capacity(std::exchange(other.m_capacity, 0))
-        , m_alloc(std::move(other.m_alloc)) {}
-    
+        , m_capacity(std::exchange(other.m_capacity, 0)) { }
+
     constexpr vector(vector&& other, const Allocator& alloc)
         : vector(alloc)
     {
-        if (alloc == other.get_allocator()) {
-            m_data = std::exchange(other.m_data, nullptr);
+        if (alloc == other._alloc()) {
+            _data() = std::exchange(other._data(), nullptr);
             m_size = std::exchange(other.m_size, 0);
             m_capacity = std::exchange(other.m_capacity, 0);
         } else {
@@ -188,9 +189,9 @@ public:
 
         if constexpr (alloc_traits::
             propagate_on_container_copy_assignment::value) {
-            if (m_alloc != other.m_alloc)
+            if (_alloc() != other._alloc())
                 shrink_to_fit();
-            m_alloc = other.m_alloc;
+            _alloc() = other._alloc();
         }
 
         insert(cbegin(), other.begin(), other.end());
@@ -204,10 +205,10 @@ public:
         if constexpr (alloc_traits::
             propagate_on_container_move_assignment::value) {
             shrink_to_fit();
-            m_alloc = std::move(other.m_alloc);
+            _alloc() = std::move(other._alloc());
         }
         else {
-            if (m_alloc != other.m_alloc) {
+            if (_alloc() != other._alloc()) {
                 // TODO: std::move_iterator
                 for (auto& item : other)
                     emplace_back(std::move(item));
@@ -216,7 +217,7 @@ public:
             shrink_to_fit();
         }
 
-        m_data = std::exchange(other.m_data, nullptr);
+        _data() = std::exchange(other._data(), nullptr);
         m_size = std::exchange(other.m_size, 0);
         m_capacity = std::exchange(other.m_capacity, 0);
         return *this;
@@ -248,55 +249,55 @@ public:
     }
 
     constexpr allocator_type get_allocator(void) const noexcept
-    { return m_alloc; }
+    { return _alloc(); }
 
     constexpr reference at(size_type pos)
     {
         // TODO: exceptions
         // if (pos >= sz)
         //     throw std::out_of_range("vector::at");
-        return m_data[pos];
+        return _data()[pos];
     }
     constexpr const_reference at(size_type pos) const
     {
         // TODO: exceptions
         // if (pos >= sz)
         //     throw std::out_of_range("vector::at");
-        return m_data[pos];
+        return _data()[pos];
     }
 
     constexpr reference operator[](size_type pos) noexcept
-    { return m_data[pos]; }
+    { return _data()[pos]; }
     constexpr const_reference operator[](size_type pos) const noexcept
-    { return m_data[pos]; }
+    { return _data()[pos]; }
 
     constexpr reference front() noexcept
-    { return m_data[0]; }
+    { return _data()[0]; }
     constexpr const_reference front() const noexcept
-    { return m_data[0]; }
+    { return _data()[0]; }
     constexpr reference back() noexcept
-    { return m_data[m_size - 1]; }
+    { return _data()[m_size - 1]; }
     constexpr const_reference back() const noexcept
-    { return m_data[m_size - 1]; }
+    { return _data()[m_size - 1]; }
 
     constexpr T* data(void) noexcept
-    { return m_data; }
+    { return _data(); }
     constexpr const T* data(void) const noexcept
-    { return m_data; }
+    { return _data(); }
 
     // TODO: std::reverse_iterator
     constexpr iterator begin() noexcept
-    { return iterator { m_data }; }
+    { return iterator { _data() }; }
     constexpr const_iterator begin() const noexcept
-    { return const_iterator { m_data }; }
+    { return const_iterator { _data() }; }
     constexpr const_iterator cbegin() const noexcept
-    { return const_iterator { m_data }; }
+    { return const_iterator { _data() }; }
     constexpr iterator end() noexcept
-    { return iterator { m_data + m_size }; }
+    { return iterator { _data() + m_size }; }
     constexpr const_iterator end() const noexcept
-    { return const_iterator { m_data + m_size }; }
+    { return const_iterator { _data() + m_size }; }
     constexpr const_iterator cend() const noexcept
-    { return const_iterator { m_data + m_size }; }
+    { return const_iterator { _data() + m_size }; }
 
     [[nodiscard]] constexpr bool empty() const noexcept
     { return m_size == 0; }
@@ -326,7 +327,7 @@ public:
 
     constexpr void shrink_to_fit()
     {
-        if (m_size != m_capacity)
+        if (m_size < m_capacity)
             _reallocate_safe(m_size);
     }
     constexpr void clear() noexcept
@@ -335,22 +336,22 @@ public:
     template <typename... Args>
     constexpr iterator emplace(const_iterator pos, Args&&... args)
     {
-        size_type idx = pos - m_data;
+        size_type idx = pos - _data();
 
-        if (!pos)
+        if (!_data())
             reserve(1);
 
         if (m_size == m_capacity)
             reserve(m_capacity * 2);
 
         for (size_type i = m_size; i > idx; --i)
-            alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i-1]));
+            alloc_traits::construct(_alloc(), _data() + i, std::move(_data()[i-1]));
 
-        alloc_traits::construct(m_alloc, m_data + idx,
+        alloc_traits::construct(_alloc(), _data() + idx,
             std::forward<Args>(args)...);
 
         ++m_size;
-        return iterator { m_data + idx };
+        return iterator { _data() + idx };
     }
 
     constexpr iterator insert(const_iterator pos, T&& val)
@@ -363,18 +364,18 @@ public:
         if (!n)
             return pos;
 
-        size_type idx = pos - m_data;
+        size_type idx = pos - _data();
         if (!pos)
             reserve(n);
 
         if (m_size + n > m_capacity)
             reserve(m_size + n);
         for (size_type i = m_size + n - 1; i >= idx + n; --i)
-            alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i-n]));
+            alloc_traits::construct(_alloc(), _data() + i, std::move(_data()[i-n]));
         for (size_type i = idx; i < idx + n; ++i)
-            alloc_traits::construct(m_alloc, m_data + i, val);
+            alloc_traits::construct(_alloc(), _data() + i, val);
         m_size += n;
-        return iterator { m_data + idx };
+        return iterator { _data() + idx };
     }
 
     // TODO: LegacyInputIterator version of this
@@ -382,7 +383,7 @@ public:
     constexpr iterator insert(const_iterator pos,
         ForwardIter first, ForwardIter last)
     {
-        size_type idx = pos - m_data;
+        size_type idx = pos - _data();
         size_type n = 0;
 
         ForwardIter tmp = first;
@@ -398,11 +399,11 @@ public:
         if (m_size + n > m_capacity)
             reserve(m_size + n);
         for (size_type i = m_size + n - 1; i >= idx + n; --i)
-            alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i-n]));
+            alloc_traits::construct(_alloc(), _data() + i, std::move(_data()[i-n]));
         for (size_type i = idx; i < idx + n; ++i)
-            alloc_traits::construct(m_alloc, m_data + i, *first++);
+            alloc_traits::construct(_alloc(), _data() + i, *first++);
         m_size += n;
-        return iterator { m_data + idx };
+        return iterator { _data() + idx };
     }
 
     constexpr iterator insert(const_iterator pos, std::initializer_list<T> init)
@@ -410,12 +411,12 @@ public:
 
     constexpr iterator erase(const_iterator pos)
     {
-        size_type idx = pos - m_data;
-        alloc_traits::destroy(m_alloc, m_data + idx);
+        size_type idx = pos - _data();
+        alloc_traits::destroy(_alloc(), _data() + idx);
         for (size_type i = idx; i < m_size - 1; ++i)
-            alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i+1]));
+            alloc_traits::construct(_alloc(), _data() + i, std::move(_data()[i+1]));
         --m_size;
-        return iterator { m_data + idx };
+        return iterator { _data() + idx };
     }
 
     constexpr iterator erase(const_iterator first, const_iterator last)
@@ -424,23 +425,23 @@ public:
         if (!n)
             return last;
 
-        size_type idx = first - m_data;
+        size_type idx = first - _data();
         for (size_type i = idx; i < idx + n; ++i)
-            alloc_traits::destroy(m_alloc, m_data + i);
+            alloc_traits::destroy(_alloc(), _data() + i);
 
         for (size_type i = idx; i < m_size - n; ++i)
-            m_alloc.construct(m_data + i, std::move(m_data[i+n]));
+            _alloc().construct(_data() + i, std::move(_data()[i+n]));
 
         m_size -= n;
-        return iterator { m_data + idx };
+        return iterator { _data() + idx };
     }
 
     constexpr void push_back(const T& val) { insert(cend(), val); }
     constexpr void push_back(T&& val) { insert(cend(), std::move(val)); }
 
     template <typename... Args>
-    constexpr void emplace_back(Args&&... args)
-    { emplace(cend(), std::forward<Args>(args)...); }
+    constexpr reference emplace_back(Args&&... args)
+    { return *emplace(cend(), std::forward<Args>(args)...); }
 
     constexpr void pop_back() { erase(--cend()); }
 
@@ -449,8 +450,8 @@ public:
         || alloc_traits::is_always_equal::value)
     {
         if (alloc_traits::propagate_on_container_swap::value)
-            std::swap(m_alloc, other.m_alloc);
-        std::swap(m_data, other.m_data);
+            std::swap(_alloc(), other.m_alloc);
+        std::swap(_data(), other.m_data);
         std::swap(m_size, other.m_size);
         std::swap(m_capacity, other.m_capacity);
     }

+ 1 - 1
global_find.sh

@@ -9,4 +9,4 @@ do_find()
     done
 }
 
-do_find "$1" "c h cpp hpp s"
+do_find "$1" "c h cpp hpp s cc rs"

+ 0 - 36
include/asm/port_io.h

@@ -1,36 +0,0 @@
-#pragma once
-
-#include <types/types.h>
-
-typedef uint16_t port_id_t;
-
-#define PORT_PIC1 (0x20)
-#define PORT_PIC2 (0xa0)
-#define PORT_PIC1_COMMAND (PORT_PIC1)
-#define PORT_PIC1_DATA ((PORT_PIC1) + 1)
-#define PORT_PIC2_COMMAND (PORT_PIC2)
-#define PORT_PIC2_DATA ((PORT_PIC2) + 1)
-
-#define PORT_KEYBOARD_COMMAND (0x64)
-#define PORT_KEYBOARD_DATA (0x60)
-
-#define PORT_PIT_CONTROL (0x43)
-#define PORT_PIT_COUNT (0x40)
-
-#define PORT_KEYDATA 0x0060u
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void asm_outb(port_id_t port_number, uint8_t data);
-extern uint8_t asm_inb(port_id_t port_number);
-
-extern void asm_hlt(void);
-extern void asm_cli(void);
-extern void asm_sti(void);
-extern void asm_enable_sse(void);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 27
include/asm/sys.h

@@ -1,27 +0,0 @@
-#pragma once
-
-#include <kernel/mem.h>
-#include <types/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void asm_switch_pd(page_t pd_addr);
-void asm_enable_paging(pd_t pd_addr);
-
-pptr_t current_pd(void);
-
-// the limit should be set on the higher 16bit
-// e.g. (n * sizeof(segment_descriptor) - 1) << 16
-void asm_load_gdt(uint32_t limit, pptr_t addr);
-
-void asm_load_tr(uint16_t index);
-
-extern const uint32_t kernel_size;
-extern char* const bss_addr;
-extern const uint32_t bss_len;
-
-#ifdef __cplusplus
-}
-#endif

+ 20 - 0
include/defs.hpp

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <types/types.h>
+
+using u8 = uint8_t;
+using u16 = uint16_t;
+using u32 = uint32_t;
+using u64 = uint64_t;
+using usize = size_t;
+
+using i8 = char;
+using i16 = short;
+using i32 = int;
+using i64 = long long;
+using isize = long;
+
+template <typename T>
+constexpr bool test(T x, T y) {
+    return (x & y) == y;
+}

+ 0 - 175
include/fs/fat.hpp

@@ -1,175 +0,0 @@
-#pragma once
-
-#include <kernel/mem.h>
-#include <kernel/vfs.hpp>
-#include <stdint.h>
-#include <string.h>
-#include <types/size.h>
-
-namespace fs::fat {
-using cluster_t = uint32_t;
-
-// for FAT32
-struct PACKED old_boot_sector {
-    uint8_t jmp_instruction[3];
-    char oem_name[8];
-    // usually 512
-    uint16_t bytes_per_sector;
-    uint8_t sectors_per_cluster;
-    // 32 for FAT32
-    uint16_t reserved_sectors;
-    // usually 2
-    uint8_t fat_copies;
-    // 0 for FAT32
-    uint16_t root_directory_entries;
-    // valid before FAT32
-    uint16_t _sectors_cnt;
-    // 0xf8 for hard disk
-    uint8_t type;
-    // valid before FAT32
-    uint16_t _sectors_per_fat;
-    // 12
-    uint16_t sectors_per_track;
-    // 2
-    uint16_t heads;
-    // 0
-    uint16_t hidden_sectors;
-};
-
-// for FAT32
-struct PACKED ext_boot_sector {
-    struct old_boot_sector old;
-    // 0
-    uint16_t hidden_sector_ext;
-    uint32_t sectors_cnt;
-    uint32_t sectors_per_fat;
-    uint16_t mirror_flags;
-    uint16_t fs_version;
-    // 2
-    cluster_t root_directory;
-    // 1
-    uint16_t fs_info_sector;
-    // usually at 6, 0x0000 or 0xffff if none
-    uint16_t backup_boot_sector;
-    uint8_t _reserved[12];
-    // for int $0x13
-    uint8_t drive_number;
-    uint8_t _reserved_for_current_head;
-    // 0x29
-    uint8_t ext_signature;
-    uint32_t serial_number;
-    char label[11];
-    char fs_type[8];
-    uint8_t _reserved_blank[420];
-    // 0x55, 0xaa
-    uint16_t magic;
-};
-
-struct PACKED fs_info_sector {
-    // 0x41615252
-    uint32_t signature_one;
-    uint8_t _reserved[480];
-    // 0x61417272
-    uint32_t signature_two;
-    // may be incorrect
-    uint32_t free_clusters;
-    // hint only
-    uint32_t next_free_cluster;
-    uint8_t _reserved_two[12];
-    // 0xaa550000
-    uint32_t sector_signature;
-};
-
-struct PACKED directory_entry {
-    char filename[8];
-    char extension[3];
-    struct PACKED {
-        uint8_t ro : 1;
-        uint8_t hidden : 1;
-        uint8_t system : 1;
-        uint8_t volume_label : 1;
-        uint8_t subdir : 1;
-        uint8_t archive : 1;
-        uint8_t _reserved : 2;
-    } attributes;
-    uint8_t _reserved;
-    uint8_t c_time_date[5];
-    uint16_t access_date;
-    uint16_t cluster_hi;
-    uint8_t m_time_date[4];
-    uint16_t cluster_lo;
-    uint32_t size;
-};
-
-// TODO: deallocate inodes when dentry is destroyed
-class fat32 : public virtual fs::vfs {
-private:
-    constexpr static uint32_t SECTOR_SIZE = 512;
-    constexpr static cluster_t EOC = 0xffffff8;
-
-private:
-    uint32_t sector_cnt;
-    uint32_t sectors_per_fat;
-    uint32_t serial_number;
-    uint32_t free_clusters;
-    uint32_t next_free_cluster_hint;
-    cluster_t root_dir;
-    cluster_t data_region_offset;
-    // TODO: use block device special node id
-    inode* device;
-    uint16_t reserved_sectors;
-    uint8_t fat_copies;
-    uint8_t sectors_per_cluster;
-    char label[12];
-    cluster_t* fat;
-
-    struct buf_object {
-        char* data;
-        int ref;
-        // bool dirty;
-    };
-    types::hash_map<cluster_t, buf_object> buf;
-
-    // buf MUST be larger than 512 bytes
-    inline void _raw_read_sector(void* buf, uint32_t sector_no);
-
-    // buf MUST be larger than 4096 bytes
-    inline void _raw_read_cluster(void* buf, cluster_t no);
-
-    // buffered version, release_cluster(cluster_no) after used
-    char* read_cluster(cluster_t no);
-    void release_cluster(cluster_t no);
-
-    static constexpr cluster_t cl(const inode* ind)
-    {
-        return ind->ino;
-    }
-
-    static inline cluster_t _rearrange(directory_entry* d)
-    {
-        return (((cluster_t)d->cluster_hi) << 16) + d->cluster_lo;
-    }
-
-    static inline size_t _write_buf_n(char* buf, size_t buf_size, const char* src, size_t n)
-    {
-        if (n <= buf_size) {
-            memcpy(buf, src, n);
-            return n;
-        } else {
-            memcpy(buf, src, buf_size);
-            return buf_size;
-        }
-    }
-
-public:
-    fat32(const fat32&) = delete;
-    explicit fat32(inode* _device);
-    ~fat32();
-
-    virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n) override;
-    virtual int inode_statx(dentry* ent, statx* st, unsigned int mask) override;
-    virtual int inode_stat(dentry* ent, struct stat* st) override;
-    virtual int inode_readdir(fs::inode* dir, size_t offset, const fs::vfs::filldir_func& callback) override;
-};
-
-}; // namespace fs::fat

+ 66 - 0
include/kernel/async/lock.hpp

@@ -0,0 +1,66 @@
+#pragma once
+
+#include <cstddef>
+
+#include <stdint.h>
+
+namespace kernel::async {
+
+using spinlock_t = unsigned long volatile;
+using lock_context_t = unsigned long;
+using preempt_count_t = std::size_t;
+
+void preempt_disable();
+void preempt_enable();
+preempt_count_t preempt_count();
+
+void init_spinlock(spinlock_t& lock);
+
+void spin_lock(spinlock_t& lock);
+void spin_unlock(spinlock_t& lock);
+
+lock_context_t spin_lock_irqsave(spinlock_t& lock);
+void spin_unlock_irqrestore(spinlock_t& lock, lock_context_t context);
+
+class mutex {
+   private:
+    spinlock_t m_lock;
+
+   public:
+    constexpr mutex() : m_lock{0} {}
+    mutex(const mutex&) = delete;
+    ~mutex();
+
+    void lock();
+    void unlock();
+
+    lock_context_t lock_irq();
+    void unlock_irq(lock_context_t state);
+};
+
+class lock_guard {
+   private:
+    mutex& m_mtx;
+
+   public:
+    explicit inline lock_guard(mutex& mtx) : m_mtx{mtx} { m_mtx.lock(); }
+    lock_guard(const lock_guard&) = delete;
+
+    inline ~lock_guard() { m_mtx.unlock(); }
+};
+
+class lock_guard_irq {
+   private:
+    mutex& m_mtx;
+    lock_context_t state;
+
+   public:
+    explicit inline lock_guard_irq(mutex& mtx) : m_mtx{mtx} {
+        state = m_mtx.lock_irq();
+    }
+    lock_guard_irq(const lock_guard_irq&) = delete;
+
+    inline ~lock_guard_irq() { m_mtx.unlock_irq(state); }
+};
+
+} // namespace kernel::async

+ 29 - 0
include/kernel/async/waitlist.hpp

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <set>
+
+#include <kernel/async/lock.hpp>
+#include <kernel/task/forward.hpp>
+
+namespace kernel::async {
+
+class wait_list {
+   private:
+    mutex m_mtx;
+    std::set<task::thread*> m_subscribers;
+
+    wait_list(const wait_list&) = delete;
+
+   public:
+    explicit wait_list() = default;
+
+    // @return whether the wait is interrupted
+    bool wait(mutex& lck);
+
+    void subscribe();
+
+    void notify_one();
+    void notify_all();
+};
+
+} // namespace kernel::async

+ 0 - 16
include/kernel/event/event.h

@@ -1,16 +0,0 @@
-#pragma once
-
-#include <kernel/input/input_event.h>
-#include <types/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void commit_input_event(struct input_event* evt);
-
-void dispatch_event(void);
-
-#ifdef __cplusplus
-}
-#endif

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

@@ -1,38 +0,0 @@
-#pragma once
-
-#include <list>
-
-#include <types/cplusplus.hpp>
-#include <types/lock.hpp>
-
-namespace kernel {
-
-namespace tasks {
-
-// declaration in kernel/process.hpp
-struct thread;
-
-} // namespace tasks
-
-class cond_var : public types::non_copyable {
-private:
-    using list_type = std::list<tasks::thread*>;
-
-    types::mutex m_mtx;
-    list_type m_subscribers;
-
-public:
-    cond_var(void) = default;
-
-    constexpr types::mutex& mtx(void)
-    {
-        return m_mtx;
-    }
-
-    /// @param lock should have already been locked
-    bool wait(types::mutex& lock);
-    void notify(void);
-    void notify_all(void);
-};
-
-} // namespace kernel

+ 35 - 0
include/kernel/hw/acpi.hpp

@@ -0,0 +1,35 @@
+#pragma once
+
+#include <types/path.hpp>
+#include <types/types.h>
+
+namespace kernel::hw::acpi {
+
+struct PACKED ACPI_table_header {
+    char signature[4];
+    uint32_t length;
+    uint8_t revision;
+    uint8_t checksum;
+    uint8_t oemid[6];
+    uint8_t oem_table_id[8];
+    uint32_t oem_revision;
+    uint32_t creator_id;
+    uint32_t creator_revision;
+};
+
+struct PACKED MCFG {
+    ACPI_table_header header;
+    uint64_t : 64;
+    struct MCFG_entry {
+        uint64_t base_address;
+        uint16_t segment_group;
+        uint8_t start_bus;
+        uint8_t end_bus;
+        uint32_t : 32;
+    } entries[];
+};
+
+int parse_acpi_tables();
+void* get_table(types::string_view name);
+
+} // namespace kernel::hw::acpi

+ 0 - 15
include/kernel/hw/keyboard.h

@@ -1,15 +0,0 @@
-#pragma once
-
-#include <types/types.h>
-
-// TODO: this whole thing needs rewriting
-
-int32_t keyboard_has_data(void);
-
-void process_keyboard_data(void);
-
-#ifdef __cplusplus
-extern "C" void handle_keyboard_interrupt(void);
-#else
-void handle_keyboard_interrupt(void);
-#endif

+ 47 - 57
include/kernel/hw/pci.hpp

@@ -1,9 +1,14 @@
 #pragma once
 
 #include <functional>
+#include <memory>
 
 #include <stdint.h>
 
+#include <types/types.h>
+
+#include <kernel/mem/phys.hpp>
+
 namespace kernel::kinit {
 
 void init_pci();
@@ -12,45 +17,11 @@ void init_pci();
 
 namespace kernel::hw::pci {
 
-struct bar_mmio {
-    uint32_t always_zero : 1;
-    uint32_t type : 2;
-    uint32_t prefetchable : 1;
-    uint32_t base_address : 28;
-};
-
-struct bar_io {
-    uint32_t always_one : 1;
-    uint32_t reserved : 1;
-    uint32_t base_address : 30;
-};
-
-union bar {
-    bar_mmio mmio;
-    bar_io io;
-};
-
-struct config_reg {
-    uint32_t addr_base;
-
-    explicit constexpr config_reg(
-        uint32_t bus, uint32_t dev, uint32_t func)
-        : addr_base(0x80000000U | (bus << 16) | (dev << 11) | (func << 8))
-    { }
-
-    // offset is in range from 0x00 to 0xff
-    uint32_t read32(uint32_t offset) const;
-    uint16_t read16(uint16_t offset) const;
-
-    // read n-th 32-bit register
-    uint32_t operator[](uint32_t n) const;
-};
-
-struct device_header_base {
+struct PACKED device_header_base {
     uint16_t vendor;
     uint16_t device;
-    uint16_t command;
-    uint16_t status;
+    uint16_t volatile command;
+    uint16_t volatile status;
     uint8_t revision_id;
     uint8_t prog_if;
     uint8_t subclass;
@@ -58,41 +29,60 @@ struct device_header_base {
     uint8_t cache_line_size;
     uint8_t latency_timer;
     uint8_t header_type;
-    uint8_t bist;
+    uint8_t volatile bist;
 };
 
-struct device_header_type0 {
-    bar bars[6];
+struct PACKED device_header_type0 {
+    device_header_base base;
+
+    uint32_t bars[6];
     uint32_t cardbus_cis_pointer;
     uint16_t subsystem_vendor_id;
     uint16_t subsystem_id;
     uint32_t expansion_rom_base_address;
     uint8_t capabilities_pointer;
-    uint8_t reserved[7];
-    uint8_t interrupt_line;
-    uint8_t interrupt_pin;
+    uint8_t __reserved[7];
+    uint8_t volatile interrupt_line;
+    uint8_t volatile interrupt_pin;
     uint8_t min_grant;
     uint8_t max_latency;
 };
 
-class pci_device {
-public:
-    config_reg reg;
-
-    uint16_t vendor;
-    uint16_t device;
-
-    uint8_t revision_id;
-    uint8_t subclass;
-    uint8_t class_code;
-    uint8_t header_type;
+struct SegmentGroup {
+    mem::physaddr<void, false> base;
+    int number;
+};
 
-    explicit pci_device(config_reg reg);
+class pci_device {
+   private:
+    std::shared_ptr<SegmentGroup> segment_group;
+    int bus;
+    int device;
+    int function;
+    void* config_space;
+
+    explicit pci_device(std::shared_ptr<SegmentGroup> segment_group, int bus,
+                        int device, int function, void* config_space);
+
+   public:
+    static pci_device* probe(std::shared_ptr<SegmentGroup> segment_group,
+                             int bus, int device, int function);
+
+    device_header_base& header() const;
+    device_header_type0& header_type0() const;
+
+    void enableBusMastering();
+
+    template <typename T>
+    inline T& at(size_t offset) const {
+        return *reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(config_space) +
+                                     offset);
+    }
 };
 
-using driver_t = std::function<int(pci_device*)>;
+using driver_t = std::function<int(pci_device&)>;
 
-pci_device* probe_device(uint8_t bus, uint8_t device, uint8_t function);
 int register_driver(uint16_t vendor, uint16_t device, driver_t drv);
+int register_driver_r(uint16_t vendor, uint16_t device, int (*drv)(pci_device*));
 
 } // namespace kernel::hw::pci

+ 15 - 33
include/kernel/hw/port.hpp

@@ -4,61 +4,43 @@
 
 namespace kernel::hw {
 
-inline uint32_t inl(uint16_t pn)
-{
+inline uint32_t inl(uint16_t pn) {
     uint32_t ret;
-    asm("inl %1, %0"
-        : "=a"(ret)
-        : "d"(pn));
+    asm volatile("inl %1, %0" : "=a"(ret) : "d"(pn));
     return ret;
 }
 
-inline uint32_t outl(uint16_t pn, uint32_t n)
-{
-    asm("outl %1, %0"
-        :
-        : "d"(pn), "a"(n));
+inline uint32_t outl(uint16_t pn, uint32_t n) {
+    asm volatile("outl %1, %0" : : "d"(pn), "a"(n));
     return n;
 }
 
-inline uint16_t inw(uint16_t pn)
-{
+inline uint16_t inw(uint16_t pn) {
     uint16_t ret;
-    asm("inw %1, %0"
-        : "=a"(ret)
-        : "d"(pn));
+    asm volatile("inw %1, %0" : "=a"(ret) : "d"(pn));
     return ret;
 }
 
-inline uint16_t outw(uint16_t pn, uint16_t n)
-{
-    asm("outw %1, %0"
-        :
-        : "d"(pn), "a"(n));
+inline uint16_t outw(uint16_t pn, uint16_t n) {
+    asm volatile("outw %1, %0" : : "d"(pn), "a"(n));
     return n;
 }
 
-inline uint8_t inb(uint16_t pn)
-{
+inline uint8_t inb(uint16_t pn) {
     uint8_t ret;
-    asm("inb %1, %0"
-        : "=a"(ret)
-        : "d"(pn));
+    asm volatile("inb %1, %0" : "=a"(ret) : "d"(pn));
     return ret;
 }
 
-inline uint8_t outb(uint16_t pn, uint8_t n)
-{
-    asm("outb %1, %0"
-        :
-        : "d"(pn), "a"(n));
+inline uint8_t outb(uint16_t pn, uint8_t n) {
+    asm volatile("outb %1, %0" : : "d"(pn), "a"(n));
     return n;
 }
 
 struct p32 {
     uint16_t mp;
 
-    explicit constexpr p32(uint16_t p) : mp(p) { }
+    explicit constexpr p32(uint16_t p) : mp(p) {}
     inline uint32_t operator*() const { return inl(mp); }
     inline uint32_t operator=(uint32_t n) const { return outl(mp, n); }
 };
@@ -66,7 +48,7 @@ struct p32 {
 struct p16 {
     uint16_t mp;
 
-    explicit constexpr p16(uint16_t p) : mp(p) { }
+    explicit constexpr p16(uint16_t p) : mp(p) {}
     inline uint16_t operator*() const { return inw(mp); }
     inline uint16_t operator=(uint16_t n) const { return outw(mp, n); }
 };
@@ -74,7 +56,7 @@ struct p16 {
 struct p8 {
     uint16_t mp;
 
-    explicit constexpr p8(uint16_t p) : mp(p) { }
+    explicit constexpr p8(uint16_t p) : mp(p) {}
     inline uint8_t operator*() const { return inb(mp); }
     inline uint8_t operator=(uint8_t n) const { return outb(mp, n); }
 };

+ 0 - 1
include/kernel/hw/serial.h → include/kernel/hw/serial.hpp

@@ -1,5 +1,4 @@
 #pragma once
-#include <asm/port_io.h>
 
 #ifdef __cplusplus
 extern "C" {

+ 0 - 17
include/kernel/hw/timer.h

@@ -1,17 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void init_pit(void);
-
-void inc_tick(void);
-
-size_t current_ticks(void);
-
-#ifdef __cplusplus
-}
-#endif

+ 11 - 0
include/kernel/hw/timer.hpp

@@ -0,0 +1,11 @@
+#pragma once
+
+#include <cstddef>
+
+namespace kernel::hw::timer {
+void init_pit(void);
+void inc_tick(void);
+
+std::size_t current_ticks(void);
+
+} // namespace kernel::hw::timer

+ 27 - 25
include/kernel/input/keycodes.h

@@ -135,20 +135,20 @@
 #define KEY_STOP 128 /* AC Stop */
 #define KEY_AGAIN 129
 #define KEY_PROPS 130 /* AC Properties */
-#define KEY_UNDO 131 /* AC Undo */
+#define KEY_UNDO 131  /* AC Undo */
 #define KEY_FRONT 132
-#define KEY_COPY 133 /* AC Copy */
-#define KEY_OPEN 134 /* AC Open */
+#define KEY_COPY 133  /* AC Copy */
+#define KEY_OPEN 134  /* AC Open */
 #define KEY_PASTE 135 /* AC Paste */
-#define KEY_FIND 136 /* AC Search */
-#define KEY_CUT 137 /* AC Cut */
-#define KEY_HELP 138 /* AL Integrated Help Center */
-#define KEY_MENU 139 /* Menu (show menu) */
-#define KEY_CALC 140 /* AL Calculator */
+#define KEY_FIND 136  /* AC Search */
+#define KEY_CUT 137   /* AC Cut */
+#define KEY_HELP 138  /* AL Integrated Help Center */
+#define KEY_MENU 139  /* Menu (show menu) */
+#define KEY_CALC 140  /* AL Calculator */
 #define KEY_SETUP 141
-#define KEY_SLEEP 142 /* SC System Sleep */
+#define KEY_SLEEP 142  /* SC System Sleep */
 #define KEY_WAKEUP 143 /* System Wake Up */
-#define KEY_FILE 144 /* AL Local Machine Browser */
+#define KEY_FILE 144   /* AL Local Machine Browser */
 #define KEY_SENDFILE 145
 #define KEY_DELETEFILE 146
 #define KEY_XFER 147
@@ -164,7 +164,7 @@
 #define KEY_MAIL 155
 #define KEY_BOOKMARKS 156 /* AC Bookmarks */
 #define KEY_COMPUTER 157
-#define KEY_BACK 158 /* AC Back */
+#define KEY_BACK 158    /* AC Back */
 #define KEY_FORWARD 159 /* AC Forward */
 #define KEY_CLOSECD 160
 #define KEY_EJECTCD 161
@@ -177,17 +177,17 @@
 #define KEY_REWIND 168
 #define KEY_PHONE 169 /* Media Select Telephone */
 #define KEY_ISO 170
-#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
+#define KEY_CONFIG 171   /* AL Consumer Control Configuration */
 #define KEY_HOMEPAGE 172 /* AC Home */
-#define KEY_REFRESH 173 /* AC Refresh */
-#define KEY_EXIT 174 /* AC Exit */
+#define KEY_REFRESH 173  /* AC Refresh */
+#define KEY_EXIT 174     /* AC Exit */
 #define KEY_MOVE 175
 #define KEY_EDIT 176
 #define KEY_SCROLLUP 177
 #define KEY_SCROLLDOWN 178
 #define KEY_KPLEFTPAREN 179
 #define KEY_KPRIGHTPAREN 180
-#define KEY_NEW 181 /* AC New */
+#define KEY_NEW 181  /* AC New */
 #define KEY_REDO 182 /* AC Redo/Repeat */
 
 #define KEY_F13 183
@@ -231,16 +231,17 @@
 #define KEY_BRIGHTNESSUP 225
 #define KEY_MEDIA 226
 
-#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video \
-                                   outputs (Monitor/LCD/TV-out/etc) */
+#define KEY_SWITCHVIDEOMODE              \
+    227 /* Cycle between available video \
+           outputs (Monitor/LCD/TV-out/etc) */
 #define KEY_KBDILLUMTOGGLE 228
 #define KEY_KBDILLUMDOWN 229
 #define KEY_KBDILLUMUP 230
 
-#define KEY_SEND 231 /* AC Send */
-#define KEY_REPLY 232 /* AC Reply */
+#define KEY_SEND 231        /* AC Send */
+#define KEY_REPLY 232       /* AC Reply */
 #define KEY_FORWARDMAIL 233 /* AC Forward Msg */
-#define KEY_SAVE 234 /* AC Save */
+#define KEY_SAVE 234        /* AC Save */
 #define KEY_DOCUMENTS 235
 
 #define KEY_BATTERY 236
@@ -251,12 +252,13 @@
 
 #define KEY_UNKNOWN 240
 
-#define KEY_VIDEO_NEXT 241 /* drive next video source */
-#define KEY_VIDEO_PREV 242 /* drive previous video source */
+#define KEY_VIDEO_NEXT 241       /* drive next video source */
+#define KEY_VIDEO_PREV 242       /* drive previous video source */
 #define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
-#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual \
-                                  brightness control is off,   \
-                                  rely on ambient */
+#define KEY_BRIGHTNESS_AUTO            \
+    244 /* Set Auto Brightness: manual \
+          brightness control is off,   \
+          rely on ambient */
 #define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
 #define KEY_DISPLAY_OFF 245 /* display device to off state */
 

+ 0 - 57
include/kernel/interrupt.h

@@ -1,57 +0,0 @@
-#pragma once
-
-#include <types/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define KERNEL_INTERRUPT_GATE_TYPE (0x8e)
-#define USER_INTERRUPT_GATE_TYPE (0xee)
-
-#define PIC_EOI (0x20)
-
-struct regs_32 {
-    uint32_t edi;
-    uint32_t esi;
-    uint32_t ebp;
-    uint32_t esp;
-    uint32_t ebx;
-    uint32_t edx;
-    uint32_t ecx;
-    uint32_t eax;
-};
-
-struct PACKED interrupt_stack {
-    struct regs_32 s_regs;
-    void* v_eip;
-    uint32_t cs;
-    uint32_t eflags;
-    uint32_t esp;
-    uint32_t ss;
-};
-
-// present: When set, the page fault was caused by a page-protection violation.
-//          When not set, it was caused by a non-present page.
-// write:   When set, the page fault was caused by a write access.
-//          When not set, it was caused by a read access.
-// user:    When set, the page fault was caused while CPL = 3.
-//          This does not necessarily mean that the page fault was a privilege violation.
-// from https://wiki.osdev.org/Exceptions#Page_Fault
-struct page_fault_error_code {
-    uint32_t present : 1;
-    uint32_t write : 1;
-    uint32_t user : 1;
-    uint32_t reserved_write : 1;
-    uint32_t instruction_fetch : 1;
-    uint32_t protection_key : 1;
-    uint32_t shadow_stack : 1;
-    uint32_t software_guard_extensions : 1;
-};
-
-void init_idt(void);
-void init_pic(void);
-
-#ifdef __cplusplus
-}
-#endif

+ 43 - 0
include/kernel/interrupt.hpp

@@ -0,0 +1,43 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <types/types.h>
+
+struct saved_regs {
+    unsigned long rax;
+    unsigned long rbx;
+    unsigned long rcx;
+    unsigned long rdx;
+    unsigned long rdi;
+    unsigned long rsi;
+    unsigned long r8;
+    unsigned long r9;
+    unsigned long r10;
+    unsigned long r11;
+    unsigned long r12;
+    unsigned long r13;
+    unsigned long r14;
+    unsigned long r15;
+    unsigned long rbp;
+};
+
+struct interrupt_stack {
+    saved_regs regs;
+    unsigned long int_no;
+    unsigned long error_code;
+    uintptr_t v_rip;
+    unsigned long cs;
+    unsigned long flags;
+    uintptr_t rsp;
+    unsigned long ss;
+};
+
+struct mmx_registers {
+    uint8_t data[512]; // TODO: list of content
+};
+
+namespace kernel::kinit {
+void init_interrupt();
+
+} // namespace kernel::kinit

+ 1 - 1
include/kernel/irq.hpp

@@ -8,4 +8,4 @@ using irq_handler_t = std::function<void()>;
 
 void register_handler(int irqno, irq_handler_t handler);
 
-};
+}; // namespace kernel::irq

+ 19 - 4
include/kernel/log.hpp

@@ -1,8 +1,23 @@
 #pragma once
 
+#include <stdio.h>
+
 #include <kernel/tty.hpp>
 
-inline void kmsg(const char* msg)
-{
-    console->print(msg);
-}
+#define kmsgf(fmt, ...)                                                  \
+    if (1) {                                                             \
+        char buf[512];                                                   \
+        snprintf(buf, sizeof(buf), fmt "\n" __VA_OPT__(, ) __VA_ARGS__); \
+        if (kernel::tty::console)                                        \
+            kernel::tty::console->print(buf);                            \
+    }
+
+#define kmsg(msg)             \
+    if (kernel::tty::console) \
+    kernel::tty::console->print(msg "\n")
+
+#ifdef NDEBUG
+#define kmsgf_debug(...)
+#else
+#define kmsgf_debug(...) kmsgf(__VA_ARGS__)
+#endif

+ 0 - 141
include/kernel/mem.h

@@ -1,141 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <types/size.h>
-
-#define PAGE_SIZE (0x1000)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// don't forget to add the initial 1m to the total
-struct mem_size_info {
-    uint16_t n_1k_blks; // memory between 1m and 16m in 1k blocks
-    uint16_t n_64k_blks; // memory above 16m in 64k blocks
-};
-
-struct e820_mem_map_entry_20 {
-    uint64_t base;
-    uint64_t len;
-    uint32_t type;
-};
-
-struct e820_mem_map_entry_24 {
-    struct e820_mem_map_entry_20 in;
-    uint32_t acpi_extension_attr;
-};
-
-/*
- * page directory entry
- *
- * p   : present (1)
- * rw  : allow write (1)
- * us  : allow user access (1)
- * pwt : todo
- * pcd : todo
- * a   : accessed for linear address translation (1)
- * d   : dirty (1) (ignored)
- * ps  : use 4MiB pages (ignored)
- * addr: page table address
- */
-typedef union pde_t {
-    uint32_t v;
-    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
- *
- * p   : present (1)
- * rw  : allow write (1)
- * us  : allow user access (1)
- * pwt : todo
- * pcd : todo
- * a   : accessed for linear address translation (1)
- * d   : dirty (1)
- * pat : todo (ignored)
- * g   : used in cr4 mode (ignored)
- * addr: physical memory address
- */
-typedef union pte_t {
-    uint32_t v;
-    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 mem.cpp
-extern uint8_t e820_mem_map[1024];
-extern uint32_t e820_mem_map_count;
-extern uint32_t e820_mem_map_entry_size;
-extern struct mem_size_info mem_size_info;
-
-#define KERNEL_HEAP_START ((void*)0xd0000000)
-#define KERNEL_HEAP_LIMIT ((void*)0xd4000000)
-
-#define EARLY_KERNEL_PD_PAGE ((page_t)0x000001)
-
-void init_mem(void);
-
-#define KERNEL_CODE_SEGMENT (0x08)
-#define KERNEL_DATA_SEGMENT (0x10)
-#define USER_CODE_SEGMENT (0x18)
-#define USER_DATA_SEGMENT (0x20)
-#define USER_CODE_SELECTOR (USER_CODE_SEGMENT | 3)
-#define USER_DATA_SELECTOR (USER_DATA_SEGMENT | 3)
-
-#define SD_TYPE_CODE_SYSTEM (0x9a)
-#define SD_TYPE_DATA_SYSTEM (0x92)
-
-#define SD_TYPE_CODE_USER (0xfa)
-#define SD_TYPE_DATA_USER (0xf2)
-
-#define SD_TYPE_TSS (0x89)
-
-typedef struct segment_descriptor_struct {
-    uint64_t limit_low : 16;
-    uint64_t base_low : 16;
-    uint64_t base_mid : 8;
-    uint64_t access : 8;
-    uint64_t limit_high : 4;
-    uint64_t flags : 4;
-    uint64_t base_high : 8;
-} segment_descriptor;
-
-// in mem.cpp
-extern segment_descriptor gdt[7];
-
-void create_segment_descriptor(
-    segment_descriptor* sd,
-    uint32_t base,
-    uint32_t limit,
-    uint32_t flags,
-    uint32_t access);
-
-#ifdef __cplusplus
-}
-#endif

+ 112 - 0
include/kernel/mem/mm_list.hpp

@@ -0,0 +1,112 @@
+#pragma once
+
+#include "paging.hpp"
+#include "vm_area.hpp"
+
+#include <set>
+
+#include <stdint.h>
+
+#include <kernel/vfs/dentry.hpp>
+
+namespace kernel::mem {
+
+constexpr uintptr_t KERNEL_SPACE_START = 0x8000000000000000ULL;
+constexpr uintptr_t USER_SPACE_MEMORY_TOP = 0x0000800000000000ULL;
+constexpr uintptr_t MMAP_MIN_ADDR = 0x0000000000001000ULL;
+constexpr uintptr_t STACK_MIN_ADDR = 0x0000700000000000ULL;
+
+class mm_list {
+   private:
+    struct comparator {
+        constexpr bool operator()(const vm_area& lhs,
+                                  const vm_area& rhs) const noexcept {
+            return lhs < rhs;
+        }
+        constexpr bool operator()(const vm_area& lhs,
+                                  uintptr_t rhs) const noexcept {
+            return lhs < rhs;
+        }
+        constexpr bool operator()(uintptr_t lhs,
+                                  const vm_area& rhs) const noexcept {
+            return lhs < rhs;
+        }
+    };
+
+   public:
+    using list_type = std::set<vm_area, comparator>;
+    using iterator = list_type::iterator;
+    using const_iterator = list_type::const_iterator;
+
+    struct map_args {
+        // MUSE BE aligned to 4kb boundary
+        uintptr_t vaddr;
+        // MUSE BE aligned to 4kb boundary
+        std::size_t length;
+
+        unsigned long flags;
+
+        const fs::rust_inode_handle* file_inode;
+        // MUSE BE aligned to 4kb boundary
+        std::size_t file_offset;
+    };
+
+   private:
+    list_type m_areas;
+    paging::pfn_t m_pt;
+    iterator m_brk{};
+
+   public:
+    // default constructor copies kernel_mms
+    explicit mm_list();
+    // copies kernel_mms and mirrors user space
+    explicit mm_list(const mm_list& other);
+
+    constexpr mm_list(mm_list&& v)
+        : m_areas(std::move(v.m_areas))
+        , m_pt(std::exchange(v.m_pt, 0))
+        , m_brk{std::move(v.m_brk)} {}
+
+    ~mm_list();
+
+    void switch_pd() const noexcept;
+
+    int register_brk(uintptr_t addr);
+    uintptr_t set_brk(uintptr_t addr);
+
+    void clear();
+
+    // split the memory block at the specified address
+    // return: iterator to the new block
+    iterator split(iterator area, uintptr_t at);
+
+    bool is_avail(uintptr_t addr) const;
+    bool is_avail(uintptr_t start, std::size_t length) const noexcept;
+
+    uintptr_t find_avail(uintptr_t hint, size_t length) const;
+
+    int unmap(iterator area, bool should_invalidate_tlb);
+    int unmap(uintptr_t start, std::size_t length, bool should_invalidate_tlb);
+
+    int mmap(const map_args& args);
+
+    constexpr vm_area* find(uintptr_t lp) {
+        auto iter = m_areas.find(lp);
+        if (iter == m_areas.end())
+            return nullptr;
+        return &iter;
+    }
+
+    constexpr const vm_area* find(uintptr_t lp) const {
+        auto iter = m_areas.find(lp);
+        if (iter == m_areas.end())
+            return nullptr;
+        return &iter;
+    }
+
+    constexpr paging::PSE get_page_table() const noexcept {
+        return paging::PSE{m_pt};
+    }
+};
+
+} // namespace kernel::mem

+ 175 - 0
include/kernel/mem/paging.hpp

@@ -0,0 +1,175 @@
+#pragma once
+
+#include <bit>
+#include <cstddef>
+#include <tuple>
+
+#include <stdint.h>
+
+#include <kernel/mem/paging_asm.h>
+#include <kernel/mem/phys.hpp>
+
+namespace kernel::mem::paging {
+
+constexpr int idx_p5(uintptr_t vaddr) noexcept {
+    return (vaddr >> 48) & 0x1ff;
+}
+constexpr int idx_p4(uintptr_t vaddr) noexcept {
+    return (vaddr >> 39) & 0x1ff;
+}
+constexpr int idx_p3(uintptr_t vaddr) noexcept {
+    return (vaddr >> 30) & 0x1ff;
+}
+constexpr int idx_p2(uintptr_t vaddr) noexcept {
+    return (vaddr >> 21) & 0x1ff;
+}
+constexpr int idx_p1(uintptr_t vaddr) noexcept {
+    return (vaddr >> 12) & 0x1ff;
+}
+
+constexpr std::tuple<int, int, int, int, int> idx_all(
+    uintptr_t vaddr) noexcept {
+    return {idx_p5(vaddr), idx_p4(vaddr), idx_p3(vaddr), idx_p2(vaddr),
+            idx_p1(vaddr)};
+}
+
+// page frame number
+// since we have large pages now, pfns are not shifted right
+using pfn_t = uintptr_t;
+
+// paging structure attributes
+using psattr_t = uintptr_t;
+
+constexpr psattr_t PA_DATA = PA_P | PA_RW | PA_NXE;
+constexpr psattr_t PA_KERNEL_DATA = PA_DATA | PA_G;
+constexpr psattr_t PA_USER_DATA = PA_DATA | PA_G | PA_US;
+
+constexpr psattr_t PA_PAGE_TABLE = PA_P | PA_RW;
+constexpr psattr_t PA_KERNEL_PAGE_TABLE = PA_PAGE_TABLE | PA_G;
+constexpr psattr_t PA_USER_PAGE_TABLE = PA_PAGE_TABLE | PA_US;
+
+constexpr psattr_t PA_DATA_HUGE = PA_DATA | PA_PS;
+constexpr psattr_t PA_KERNEL_DATA_HUGE = PA_DATA_HUGE | PA_G;
+constexpr psattr_t PA_USER_DATA_HUGE = PA_DATA_HUGE | PA_US;
+
+constexpr psattr_t PA_ANONYMOUS_PAGE = PA_P | PA_US | PA_COW | PA_ANON;
+constexpr psattr_t PA_MMAPPED_PAGE = PA_US | PA_COW | PA_ANON | PA_MMAP;
+
+namespace __inner {
+    using pse_t = uint64_t;
+
+} // namespace __inner
+
+class PSE {
+    physaddr<__inner::pse_t> m_ptrbase;
+
+   public:
+    explicit constexpr PSE(uintptr_t pptr) noexcept : m_ptrbase{pptr} {}
+
+    constexpr void clear() noexcept { *m_ptrbase = 0; }
+
+    constexpr void set(psattr_t attributes, pfn_t pfn) {
+        *m_ptrbase = (attributes & PA_MASK) | (pfn & ~PA_MASK);
+    }
+
+    constexpr pfn_t pfn() const noexcept { return *m_ptrbase & ~PA_MASK; }
+
+    constexpr psattr_t attributes() const noexcept {
+        return *m_ptrbase & PA_MASK;
+    }
+
+    constexpr PSE operator[](std::size_t nth) const noexcept {
+        return PSE{m_ptrbase.phys() + 8 * nth};
+    }
+
+    constexpr PSE parse() const noexcept { return PSE{*m_ptrbase & ~PA_MASK}; }
+};
+
+constexpr physaddr<void> KERNEL_PAGE_TABLE_PHYS_ADDR{KERNEL_PML4};
+constexpr PSE KERNEL_PAGE_TABLE{KERNEL_PML4};
+
+constexpr unsigned long PAGE_PRESENT = 0x00010000;
+constexpr unsigned long PAGE_BUDDY = 0x00020000;
+constexpr unsigned long PAGE_SLAB = 0x00040000;
+
+struct page {
+    // TODO: use atomic
+    unsigned long refcount;
+    unsigned long flags;
+
+    page* next;
+    page* prev;
+};
+
+inline page* PAGE_ARRAY;
+
+void create_zone(uintptr_t start, uintptr_t end);
+void mark_present(uintptr_t start, uintptr_t end);
+
+[[nodiscard]] page* alloc_page();
+// order represents power of 2
+[[nodiscard]] page* alloc_pages(unsigned order);
+
+// order represents power of 2
+void free_pages(page* page, unsigned order);
+void free_page(page* page);
+
+// order represents power of 2
+void free_pages(pfn_t pfn, unsigned order);
+void free_page(pfn_t pfn);
+
+// clear the page all zero
+[[nodiscard]] pfn_t alloc_page_table();
+
+pfn_t page_to_pfn(page* page);
+page* pfn_to_page(pfn_t pfn);
+
+void increase_refcount(page* page);
+
+constexpr unsigned long PAGE_FAULT_P = 0x00000001;
+constexpr unsigned long PAGE_FAULT_W = 0x00000002;
+constexpr unsigned long PAGE_FAULT_U = 0x00000004;
+constexpr unsigned long PAGE_FAULT_R = 0x00000008;
+constexpr unsigned long PAGE_FAULT_I = 0x00000010;
+constexpr unsigned long PAGE_FAULT_PK = 0x00000020;
+constexpr unsigned long PAGE_FAULT_SS = 0x00000040;
+constexpr unsigned long PAGE_FAULT_SGX = 0x00008000;
+
+void handle_page_fault(unsigned long err);
+
+class vaddr_range {
+    std::size_t n;
+
+    int idx4;
+    int idx3;
+    int idx2;
+    int idx1;
+
+    PSE pml4;
+    PSE pdpt;
+    PSE pd;
+    PSE pt;
+
+    uintptr_t m_start;
+    uintptr_t m_end;
+
+    bool is_privilege;
+
+   public:
+    explicit vaddr_range(pfn_t pt, uintptr_t start, uintptr_t end,
+                         bool is_privilege = false);
+    explicit vaddr_range(std::nullptr_t);
+
+    vaddr_range begin() const noexcept;
+    vaddr_range end() const noexcept;
+
+    PSE operator*() const noexcept;
+
+    vaddr_range& operator++();
+    operator bool() const noexcept;
+
+    // compares remaining pages to iterate
+    bool operator==(const vaddr_range& other) const noexcept;
+};
+
+} // namespace kernel::mem::paging

+ 27 - 0
include/kernel/mem/paging_asm.h

@@ -0,0 +1,27 @@
+
+#define KERNEL_IMAGE_PADDR         0x400000
+#define KERNEL_STAGE1_PADDR        0x001000
+#define KERNEL_PML4                0x002000
+#define KERNEL_PDPT_PHYS_MAPPING   0x003000
+#define KERNEL_PDPT_KERNEL_SPACE   0x004000
+#define KERNEL_PD_KIMAGE           0x005000
+#define KERNEL_PT_KIMAGE           0x006000
+#define KERNEL_PD_STRUCT_PAGE_ARR  0x007000
+#define EMPTY_PAGE_PFN             0x008000
+
+#define KERNEL_BSS_HUGE_PAGE       0x200000
+
+#define PA_P    0x0000000000000001
+#define PA_RW   0x0000000000000002
+#define PA_US   0x0000000000000004
+#define PA_PWT  0x0000000000000008
+#define PA_PCD  0x0000000000000010
+#define PA_A    0x0000000000000020
+#define PA_D    0x0000000000000040
+#define PA_PS   0x0000000000000080
+#define PA_G    0x0000000000000100
+#define PA_COW  0x0000000000000200
+#define PA_MMAP 0x0000000000000400
+#define PA_ANON 0x0000000000000800
+#define PA_NXE  0x8000000000000000
+#define PA_MASK 0xfff0000000000fff

+ 53 - 0
include/kernel/mem/phys.hpp

@@ -0,0 +1,53 @@
+#pragma once
+
+#include <bit>
+#include <cstddef>
+
+#include <stdint.h>
+
+#include <types/types.h>
+
+#include <kernel/mem/types.hpp>
+
+namespace kernel::mem {
+
+template <typename T, bool Cached = true>
+class physaddr {
+    static constexpr uintptr_t PHYS_OFFSET =
+        Cached ? 0xffffff0000000000ULL : 0xffffff4000000000ULL;
+
+    uintptr_t m_ptr;
+
+   public:
+    explicit constexpr physaddr(uintptr_t ptr) : m_ptr{ptr} {}
+    explicit constexpr physaddr(std::nullptr_t) : m_ptr{} {}
+
+    // cast to non-pointer types is prohibited
+    template <typename U, typename = std::enable_if_t<std::is_pointer_v<U>>>
+    constexpr U cast_to() const noexcept {
+        return std::bit_cast<U>(m_ptr + PHYS_OFFSET);
+    }
+
+    constexpr operator T*() const noexcept { return cast_to<T*>(); }
+    constexpr T* operator->() const noexcept { return *this; }
+    constexpr uintptr_t phys() const noexcept { return m_ptr; }
+};
+
+//  gdt[0]:  null
+//  gdt[1]:  kernel code
+//  gdt[2]:  kernel data
+//  gdt[3]:  user code
+//  gdt[4]:  user data
+//  gdt[5]:  user code compability mode
+//  gdt[6]:  user data compability mode
+//  gdt[7]:  thread local 32bit
+//  gdt[8]:  tss descriptor low
+//  gdt[9]:  tss descriptor high
+//  gdt[10]: ldt descriptor low
+//  gdt[11]: ldt descriptor high
+//  gdt[12]: null segment(in ldt)
+//  gdt[13]: thread local 64bit(in ldt)
+// &gdt[14]: tss of 0x68 bytes from here
+constexpr physaddr<uint64_t> gdt{0x00000000 + 1 - 1};
+
+} // namespace kernel::mem

+ 37 - 0
include/kernel/mem/slab.hpp

@@ -0,0 +1,37 @@
+#pragma once
+
+#include <cstddef>
+#include <type_traits>
+
+#include <stdint.h>
+
+namespace kernel::mem {
+
+struct slab_cache;
+
+struct slab_head {
+    slab_cache* cache;
+
+    slab_head* next;
+    slab_head* prev;
+
+    void* free;
+
+    unsigned int free_count;
+    unsigned int obj_size;
+};
+
+struct slab_cache {
+    slab_head* slabs_empty;
+    slab_head* slabs_partial;
+    slab_head* slabs_full;
+
+    std::size_t obj_size;
+};
+
+void init_slab_cache(slab_cache* cache, std::size_t obj_size);
+
+void* slab_alloc(slab_cache* cache);
+void slab_free(void* ptr);
+
+} // namespace kernel::mem

+ 36 - 0
include/kernel/mem/types.hpp

@@ -0,0 +1,36 @@
+#pragma once
+
+#include <cstddef>
+
+#include <stdint.h>
+
+namespace kernel::mem {
+
+struct gdt_entry {
+    uint64_t limit_low : 16;
+    uint64_t base_low : 16;
+    uint64_t base_mid : 8;
+    uint64_t access : 8;
+    uint64_t limit_high : 4;
+    uint64_t flags : 4;
+    uint64_t base_high : 8;
+};
+
+struct e820_mem_map_entry {
+    uint64_t base;
+    uint64_t len;
+    uint32_t type;
+
+    // might not be valid
+    uint32_t acpi_extension_attr;
+};
+
+namespace info {
+    inline std::size_t memory_size;
+    inline std::size_t e820_entry_count;
+    inline std::size_t e820_entry_length;
+    inline e820_mem_map_entry e820_entries[(1024 - 16) / 24];
+
+} // namespace info
+
+} // namespace kernel::mem

+ 60 - 0
include/kernel/mem/vm_area.hpp

@@ -0,0 +1,60 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <kernel/vfs.hpp>
+#include <kernel/vfs/dentry.hpp>
+
+namespace kernel::mem {
+
+constexpr unsigned long MM_WRITE = 0x00000000'00000001;
+constexpr unsigned long MM_EXECUTE = 0x00000000'00000002;
+constexpr unsigned long MM_MAPPED = 0x00000000'00000004;
+constexpr unsigned long MM_ANONYMOUS = 0x00000000'00000008;
+constexpr unsigned long MM_INTERNAL_MASK = 0xffffffff'00000000;
+constexpr unsigned long MM_BREAK = 0x80000000'00000000;
+
+struct vm_area {
+    uintptr_t start;
+    uintptr_t end;
+
+    unsigned long flags;
+
+    const fs::rust_inode_handle* mapped_file;
+    std::size_t file_offset;
+
+    constexpr bool is_avail(uintptr_t ostart, uintptr_t oend) const noexcept {
+        return (ostart >= end || oend <= start);
+    }
+
+    constexpr bool operator<(const vm_area& rhs) const noexcept {
+        return end <= rhs.start;
+    }
+    constexpr bool operator<(uintptr_t rhs) const noexcept {
+        return end <= rhs;
+    }
+    friend constexpr bool operator<(uintptr_t lhs,
+                                    const vm_area& rhs) noexcept {
+        return lhs < rhs.start;
+    }
+
+    constexpr vm_area(uintptr_t start, unsigned long flags, uintptr_t end,
+                      const fs::rust_inode_handle* mapped_file = nullptr,
+                      std::size_t offset = 0)
+        : start{start}
+        , end{end}
+        , flags{flags}
+        , mapped_file{mapped_file}
+        , file_offset{offset} {}
+
+    constexpr vm_area(uintptr_t start, unsigned long flags,
+                      const fs::rust_inode_handle* mapped_file = nullptr,
+                      std::size_t offset = 0)
+        : start{start}
+        , end{start}
+        , flags{flags}
+        , mapped_file{mapped_file}
+        , file_offset{offset} {}
+};
+
+} // namespace kernel::mem

+ 0 - 405
include/kernel/mm.hpp

@@ -1,405 +0,0 @@
-#pragma once
-
-#include <set>
-#include <vector>
-#include <bit>
-#include <cstddef>
-#include <utility>
-
-#include <kernel/mem.h>
-#include <kernel/vfs.hpp>
-#include <stdint.h>
-#include <types/allocator.hpp>
-#include <types/cplusplus.hpp>
-#include <types/size.h>
-#include <types/status.h>
-#include <types/types.h>
-
-#define invalidate_tlb(addr) asm("invlpg (%0)" \
-                                 :             \
-                                 : "r"(addr)   \
-                                 : "memory")
-
-#define memory_fence asm volatile("" ::: "memory")
-
-constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
-
-constexpr uint32_t PAGE_COW = (1 << 0);
-constexpr uint32_t PAGE_MMAP = (1 << 1);
-#define PAGE_COW PAGE_COW
-#define PAGE_MMAP PAGE_MMAP
-
-struct page {
-    page_t phys_page_id;
-    size_t* ref_count;
-    // 0 :11 : pte_index
-    // 12:31 : pt_page
-    uint32_t pg_pteidx;
-    mutable uint32_t 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
-// @param offset MUST be aligned to 4kb
-int mmap(
-    void* hint,
-    size_t len,
-    fs::inode* file,
-    size_t offset,
-    int write,
-    int priv);
-
-template <uint32_t base, uint32_t expo>
-constexpr uint32_t pow()
-{
-    if constexpr (expo == 0)
-        return 1;
-    if constexpr (expo == 1)
-        return base;
-    if constexpr (expo % 2 == 0)
-        return pow<base, expo / 2>() * pow<base, expo / 2>();
-    else
-        return pow<base, expo / 2>() * pow<base, expo / 2 + 1>();
-}
-
-template <int N>
-constexpr uint32_t align_down(uint32_t v)
-{
-    return v & ~(pow<2, N>() - 1);
-}
-template <int N>
-constexpr void* align_down(void* v)
-{
-    return std::bit_cast<void*>(align_down<N>(std::bit_cast<uint32_t>(v)));
-}
-template <int N>
-constexpr uint32_t align_up(uint32_t v)
-{
-    return align_down<N>(v + pow<2, N>() - 1);
-}
-template <int N>
-constexpr void* align_up(void* v)
-{
-    return std::bit_cast<void*>(align_up<N>(std::bit_cast<uint32_t>(v)));
-}
-
-constexpr size_t vptrdiff(void* p1, void* p2)
-{
-    auto* _p1 = static_cast<std::byte*>(p1);
-    auto* _p2 = static_cast<std::byte*>(p2);
-    return _p1 - _p2;
-}
-
-constexpr void* vptradd(void* p, std::size_t off)
-{
-    auto* _p = static_cast<std::byte*>(p);
-    return _p + off;
-}
-
-void dealloc_pd(page_t pd);
-
-// allocate a struct page together with the raw page
-page allocate_page(void);
-void free_page(page* pg);
-
-// TODO: this is for alloc_kstack()
-// CHANGE THIS
-page_t __alloc_raw_page(void);
-void __free_raw_page(page_t pg);
-
-namespace kernel {
-
-void* pmap(page_t pg, bool cached = true);
-void pfree(page_t pg);
-
-class paccess : public types::non_copyable {
-private:
-    page_t m_pg;
-    void* m_ptr;
-
-public:
-    paccess(void) = delete;
-    paccess(paccess&&) = delete;
-    paccess& operator=(paccess&&) = delete;
-
-    constexpr explicit paccess(page_t pg, bool cached = true)
-        : m_pg(pg)
-    {
-        m_ptr = pmap(pg, cached);
-    }
-    constexpr void* ptr(void) const
-    {
-        return m_ptr;
-    }
-    ~paccess()
-    {
-        pfree(m_pg);
-    }
-};
-
-namespace memory {
-
-struct mm {
-public:
-    using pages_vector = std::vector<page,
-        types::allocator_adapter<page, types::kernel_ident_allocator>>;
-
-public:
-    void* start {};
-    struct mm_attr {
-        uint32_t write : 1;
-        uint32_t system : 1;
-        uint32_t mapped : 1;
-    } attr {};
-    pages_vector* pgs {};
-    fs::inode* mapped_file {};
-    size_t file_offset {};
-
-public:
-    constexpr void* end() const noexcept
-    { return vptradd(start, pgs->size() * PAGE_SIZE); }
-    constexpr bool is_kernel_space() const noexcept
-    { return attr.system; }
-    constexpr bool is_avail(void* ostart, void* oend) const noexcept
-    {
-        void* m_start = start;
-        void* m_end = end();
-
-        return (ostart >= m_end || oend <= m_start);
-    }
-
-    void append_page(pd_t pd, const page& pg, uint32_t attr, bool priv);
-
-    /**
-     * @brief Splits the memory block at the specified address.
-     * 
-     * @param addr The address at which the memory block will be split.
-     * @return The new memory block created after splitting.
-     */
-    mm split(void* addr);
-
-    constexpr bool operator<(const mm& rhs) const noexcept
-    { return end() <= rhs.start; }
-    constexpr bool operator<(void* rhs) const noexcept
-    { return end() <= rhs; }
-    friend constexpr bool operator<(void* lhs, const mm& rhs) noexcept
-    { return lhs < rhs.start; }
-};
-
-class mm_list {
-private:
-    struct comparator {
-        constexpr bool operator()(const mm& lhs, const mm& rhs) const noexcept
-        { return lhs < rhs; }
-        constexpr bool operator()(const mm& lhs, void* rhs) const noexcept
-        { return lhs < rhs; }
-        constexpr bool operator()(void* lhs, const mm& rhs) const noexcept
-        { return lhs < rhs; }
-    };
-
-public:
-    using list_type = std::set<mm, comparator,
-        types::allocator_adapter<mm, types::kernel_ident_allocator>>;
-    using iterator = list_type::iterator;
-    using const_iterator = list_type::const_iterator;
-
-public:
-    static inline mm_list* s_kernel_mms;
-
-private:
-    list_type m_areas;
-    page_t m_pd;
-    mm* m_brk {};
-
-public:
-    // for system initialization only
-    explicit constexpr mm_list(page_t pd)
-        : m_pd(pd) { }
-
-    // default constructor copies kernel_mms
-    explicit mm_list();
-    // copies kernel_mms and mirrors user space
-    explicit mm_list(const mm_list& other);
-
-    constexpr mm_list(mm_list&& v)
-        : m_areas(std::move(v.m_areas))
-        , m_pd(std::exchange(v.m_pd, 0)) { }
-
-    ~mm_list();
-    void switch_pd() const;
-
-    int register_brk(void* addr);
-    void* set_brk(void* addr);
-
-    void* find_avail(void* hint, size_t len, bool priv) const;
-
-    int unmap(void* start, size_t len, bool priv);
-
-    constexpr mm& addarea(void* start, bool w, bool system)
-    {
-        auto [ iter, inserted ] = m_areas.emplace(mm {
-            .start = start,
-            .attr {
-                .write = w,
-                .system = system,
-                .mapped = 0,
-            },
-            .pgs = types::_new<types::kernel_ident_allocator, mm::pages_vector>(),
-        });
-        assert(inserted);
-        return *iter;
-    }
-
-    mm& add_empty_area(void* start, std::size_t page_count,
-        uint32_t page_attr, bool w, bool system);
-
-    constexpr void clear_user()
-    {
-        for (auto iter = m_areas.begin(); iter != m_areas.end(); ) {
-            if (iter->is_kernel_space()) {
-                ++iter;
-                continue;
-            }
-
-            this->unmap(*iter);
-            iter = m_areas.erase(iter);
-        }
-        m_brk = nullptr;
-    }
-
-    inline void unmap(mm& area)
-    {
-        int i = 0;
-
-        // TODO:
-        // if there are more than 4 pages, calling invlpg
-        // should be faster. otherwise, we use movl cr3
-        // bool should_invlpg = (area->pgs->size() > 4);
-
-        for (auto& pg : *area.pgs) {
-            kernel::paccess pa(pg.pg_pteidx >> 12);
-            auto pt = (pt_t)pa.ptr();
-            assert(pt);
-            auto* pte = *pt + (pg.pg_pteidx & 0xfff);
-            pte->v = 0;
-
-            free_page(&pg);
-
-            invalidate_tlb((uint32_t)area.start + (i++) * PAGE_SIZE);
-        }
-        types::pdelete<types::kernel_ident_allocator>(area.pgs);
-    }
-
-    constexpr mm* find(void* lp)
-    {
-        auto iter = m_areas.find(lp);
-        if (iter == m_areas.end())
-            return nullptr;
-        return &*iter;
-    }
-    constexpr const mm* find(void* lp) const
-    {
-        auto iter = m_areas.find(lp);
-        if (iter == m_areas.end())
-            return nullptr;
-        return &*iter;
-    }
-
-    constexpr bool is_avail(void* start, size_t len) const noexcept
-    {
-        start = align_down<12>(start);
-        len = vptrdiff(align_up<12>(vptradd(start, len)), start);
-        for (const auto& area : m_areas) {
-            if (!area.is_avail(start, vptradd(start, len)))
-                return false;
-        }
-        return true;
-    }
-
-    constexpr bool is_avail(void* addr) const
-    {
-        auto iter = m_areas.find(addr);
-        return iter == m_areas.end();
-    }
-};
-
-} // namespace memory
-
-} // namespace kernel
-
-// global variables
-inline page empty_page;
-// --------------------------------
-
-// inline constexpr page* lto_page(mm* mm_area, void* l_ptr)
-// {
-//     size_t offset = vptrdiff(l_ptr, mm_area->start);
-//     return &mm_area->pgs->at(offset / PAGE_SIZE);
-// }
-// inline constexpr page_t to_page(pptr_t ptr)
-// {
-//     return ptr >> 12;
-// }
-// inline constexpr size_t to_pdi(page_t pg)
-// {
-//     return pg >> 10;
-// }
-// inline constexpr size_t to_pti(page_t pg)
-// {
-//     return pg & (1024 - 1);
-// }
-// inline constexpr pptr_t to_pp(page_t p)
-// {
-//     return p << 12;
-// }
-constexpr size_t v_to_pdi(void* addr)
-{
-    return std::bit_cast<uint32_t>(addr) >> 22;
-}
-constexpr size_t v_to_pti(void* addr)
-{
-    return (std::bit_cast<uint32_t>(addr) >> 12) & 0x3ff;
-}
-// inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
-// {
-//     return *pt + to_pti(pg);
-// }
-// inline void* to_vp(page_t pg)
-// {
-//     return ptovp(to_pp(pg));
-// }
-// inline pd_t to_pd(page_t pg)
-// {
-//     return reinterpret_cast<pd_t>(to_vp(pg));
-// }
-// inline pt_t to_pt(page_t pg)
-// {
-//     return reinterpret_cast<pt_t>(to_vp(pg));
-// }
-// inline pt_t to_pt(pde_t* pde)
-// {
-//     return to_pt(pde->in.pt_page);
-// }
-// inline pde_t* to_pde(pd_t pd, void* addr)
-// {
-//     return *pd + lto_pdi((pptr_t)addr);
-// }
-// inline pte_t* to_pte(pt_t pt, void* addr)
-// {
-//     return *pt + lto_pti((pptr_t)addr);
-// }
-// inline pte_t* to_pte(pde_t* pde, void* addr)
-// {
-//     return to_pte(to_pt(pde), addr);
-// }
-// inline pte_t* to_pte(pd_t pd, void* addr)
-// {
-//     return to_pte(to_pde(pd, addr), addr);
-// }
-// inline pte_t* to_pte(pde_t* pde, page_t pg)
-// {
-//     return to_pte(to_pt(pde), pg);
-// }

+ 23 - 20
include/kernel/module.hpp

@@ -1,34 +1,37 @@
 #pragma once
 
+#include <memory>
+
 #include <types/types.h>
 
-#define INTERNAL_MODULE(name, func) \
-    SECTION(".kmods") __attribute__((used)) \
-    kernel::module::module_loader const name = (func)
+#define MODULE_LOADER(name) \
+    static std::unique_ptr<kernel::kmod::kmod> __module##name##_loader()
+
+#define INTERNAL_MODULE(name, type)                                         \
+    MODULE_LOADER(name);                                                    \
+    SECTION(".kmods")                                                       \
+    __attribute__((used))                                                   \
+    std::unique_ptr<kernel::kmod::kmod> (*const __module##name##_entry)() = \
+        __module##name##_loader;                                            \
+    MODULE_LOADER(name) {                                                   \
+        return std::make_unique<type>();                                    \
+    }
 
-namespace kernel::module {
+namespace kernel::kmod {
 
-struct module {
+struct kmod {
     const char* const name;
 
-    explicit module(const char* name);
+    explicit kmod(const char* name);
 
-    virtual ~module() = default;
-    module(const module&) = delete;
-    module& operator=(const module&) = delete;
+    virtual ~kmod() = default;
+    kmod(const kmod&) = delete;
+    kmod& operator=(const kmod&) = delete;
 
     virtual int init() = 0;
 };
 
-using module_loader = module* (*)();
-
-constexpr int MODULE_SUCCESS = 0;
-constexpr int MODULE_FAILED = 1;
-constexpr int MODULE_DELAYED = 2;
-
-// TODO: unique_ptr and Deleter
-int insmod(module* mod);
-
-extern "C" module_loader kmod_loaders_start[];
+extern "C" std::unique_ptr<kmod> (*const KMOD_LOADERS_START[])();
+void load_internal_modules();
 
-} // namespace kernel::module
+} // namespace kernel::kmod

+ 76 - 343
include/kernel/process.hpp

@@ -1,270 +1,76 @@
 #pragma once
 
-#include <map>
 #include <list>
-#include <memory>
-#include <queue>
+#include <map>
 #include <set>
 #include <tuple>
 #include <utility>
 
-#include <errno.h>
+#include <assert.h>
 #include <fcntl.h>
-#include <kernel/event/evtqueue.hpp>
-#include <kernel/interrupt.h>
-#include <kernel/mm.hpp>
-#include <kernel/signal.hpp>
-#include <kernel/task.h>
-#include <kernel/tty.hpp>
-#include <kernel/vfs.hpp>
 #include <stdint.h>
 #include <sys/types.h>
+
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
-#include <types/hash_map.hpp>
 #include <types/path.hpp>
-#include <types/status.h>
-#include <types/string.hpp>
 #include <types/types.h>
 
-class process;
-
-namespace kernel::tasks {
-
-struct thread;
+#include <kernel/async/waitlist.hpp>
+#include <kernel/interrupt.hpp>
+#include <kernel/mem/mm_list.hpp>
+#include <kernel/mem/paging.hpp>
+#include <kernel/signal.hpp>
+#include <kernel/task/current.hpp>
+#include <kernel/task/thread.hpp>
+#include <kernel/tty.hpp>
+#include <kernel/user/thread_local.hpp>
+#include <kernel/vfs.hpp>
+#include <kernel/vfs/dentry.hpp>
+#include <kernel/vfs/filearr.hpp>
 
-} // namespace kernel::tasks
+class process;
 
 class proclist;
-class readyqueue;
 
 inline process* volatile current_process;
-inline kernel::tasks::thread* volatile current_thread;
 inline proclist* procs;
-inline readyqueue* readythds;
-
-inline tss32_t tss;
 
 struct process_attr {
     uint16_t system : 1;
     uint16_t zombie : 1 = 0;
 };
 
-struct thread_attr {
-    uint32_t system : 1;
-    uint32_t ready : 1;
-    uint32_t wait : 1;
-};
-
-namespace kernel::tasks {
-
-using tid_t = uint32_t;
-
-struct thread {
-private:
-    void alloc_kstack(void);
-    void free_kstack(uint32_t p);
-
-public:
-    uint32_t* esp;
-    uint32_t pkstack;
-    pid_t owner;
-    thread_attr attr;
-
-    int* __user set_child_tid {};
-    int* __user clear_child_tid {};
-
-    types::string<> name {};
-
-    explicit inline thread(types::string<> name, pid_t owner)
-        : owner { owner }
-        , attr { .system = 1, .ready = 1, .wait = 0, }
-        , name { name }
-    {
-        alloc_kstack();
-    }
-
-    inline thread(const thread& val, pid_t owner)
-        : owner { owner }, attr { val.attr }, name { val.name }
-    {
-        alloc_kstack();
-    }
-
-    constexpr thread(thread&& val) = default;
-    inline ~thread() { free_kstack(pkstack); }
-
-    constexpr tid_t tid() const { return pkstack; }
-
-    constexpr bool operator==(const thread& rhs) const
-    { return pkstack == rhs.pkstack; }
-    constexpr bool operator<(const thread& rhs) const
-    { return pkstack < rhs.pkstack; }
-};
-
-}
-
-class filearr {
-public:
-    using array_type = std::map<int, std::shared_ptr<fs::file>>;
-
-private:
-    array_type arr;
-    std::priority_queue<int, std::vector<int>, std::greater<int>> _fds;
-    int _greatest_fd;
-
-private:
-    constexpr int next_fd()
-    {
-        if (_fds.empty())
-            return _greatest_fd++;
-        int retval = _fds.top();
-        _fds.pop();
-        return retval;
-    }
-
-public:
-    constexpr filearr(const filearr&) = delete;
-    constexpr filearr& operator=(const filearr&) = delete;
-    constexpr filearr& operator=(filearr&&) = delete;
-    constexpr filearr(void) = default;
-    constexpr filearr(filearr&& val) = default;
-
-    constexpr int dup(int old_fd)
-    {
-        return dup2(old_fd, next_fd());
-    }
-
-    // TODO: the third parameter should be int flags
-    //       determining whether the fd should be closed
-    //       after exec() (FD_CLOEXEC)
-    constexpr int dup2(int old_fd, int new_fd)
-    {
-        close(new_fd);
-
-        auto iter = arr.find(old_fd);
-        if (!iter)
-            return -EBADF;
-
-        this->arr.emplace(new_fd, iter->second);
-        return new_fd;
-    }
-
-    constexpr void dup_all(const filearr& orig)
-    {
-        this->_fds = orig._fds;
-        this->_greatest_fd = orig._greatest_fd;
-        for (auto [ fd, fp ] : orig.arr)
-            this->arr.emplace(fd, fp);
-    }
-
-    constexpr fs::file* operator[](int i) const
-    {
-        auto iter = arr.find(i);
-        if (!iter)
-            return nullptr;
-        return iter->second.get();
-    }
-
-    int pipe(int pipefd[2])
-    {
-        std::shared_ptr<fs::pipe> ppipe { new fs::pipe };
-
-        bool inserted = false;
-        int fd = next_fd();
-        std::tie(std::ignore, inserted) = arr.emplace(fd,
-            std::shared_ptr<fs::file> {
-                new fs::fifo_file(nullptr, {
-                    .read = 1,
-                    .write = 0,
-                    .close_on_exec = 0,
-                }, ppipe),
-        });
-        assert(inserted);
-
-        // TODO: use copy_to_user()
-        pipefd[0] = fd;
-
-        fd = next_fd();
-        std::tie(std::ignore, inserted) = arr.emplace(fd,
-            std::shared_ptr<fs::file> {
-                new fs::fifo_file(nullptr, {
-                    .read = 0,
-                    .write = 1,
-                    .close_on_exec = 0,
-                }, ppipe),
-        });
-        assert(inserted);
-
-        // TODO: use copy_to_user()
-        pipefd[1] = fd;
-
-        return 0;
-    }
-
-    int open(const process& current, const types::path& filepath, int flags, mode_t mode);
-
-    constexpr void close(int fd)
-    {
-        auto iter = arr.find(fd);
-        if (!iter)
-            return;
-
-        iter->second->close();
-        _fds.push(fd);
-        arr.erase(iter);
-    }
-
-    constexpr void onexec()
-    {
-        for (auto&& [ fd, fp ] : arr) {
-            if (fp->flags.close_on_exec)
-                close(fd);
-        }
-    }
-
-    constexpr void close_all(void)
-    {
-        for (auto&& [ fd, fp ] : arr) {
-            fp->close();
-            _fds.push(fd);
-        }
-        arr.clear();
-    }
-
-    constexpr ~filearr()
-    {
-        close_all();
-    }
-};
-
 class process {
-public:
+   public:
     struct wait_obj {
         pid_t pid;
         int code;
     };
 
-public:
-    kernel::memory::mm_list mms {};
-    std::set<kernel::tasks::thread> thds;
-    kernel::cond_var cv_wait;
-    std::list<wait_obj> waitlist;
-    process_attr attr {};
-    filearr files;
-    types::path pwd;
-    kernel::signal_list signals;
-    mode_t umask { 0022 };
-
-    pid_t pid {};
-    pid_t ppid {};
-    pid_t pgid {};
-    pid_t sid {};
-
-    tty* control_tty {};
-    fs::vfs::dentry* root { fs::fs_root };
+   public:
+    kernel::mem::mm_list mms{};
+    std::set<kernel::task::thread> thds;
+    kernel::async::wait_list waitlist;
+
+    kernel::async::mutex mtx_waitprocs;
+    std::list<wait_obj> waitprocs;
+
+    process_attr attr{};
+    fs::filearray files;
+    fs::dentry_pointer cwd{};
+    mode_t umask{0022};
+
+    pid_t pid{};
+    pid_t ppid{};
+    pid_t pgid{};
+    pid_t sid{};
+
+    kernel::tty::tty* control_tty{};
+    struct fs::fs_context fs_context;
     std::set<pid_t> children;
 
-public:
+   public:
     process(const process&) = delete;
     explicit process(const process& parent, pid_t pid);
 
@@ -272,53 +78,33 @@ public:
     // DO NOT use this after the system is on
     explicit process(pid_t pid, pid_t ppid);
 
-    constexpr bool is_system(void) const
-    { return attr.system; }
-    constexpr bool is_zombie(void) const
-    { return attr.zombie; }
+    constexpr bool is_system(void) const { return attr.system; }
+    constexpr bool is_zombie(void) const { return attr.zombie; }
+
+    void send_signal(kernel::signal_list::signo_type signal);
 };
 
 class proclist final {
-public:
-    using list_type = std::map<pid_t, process>;
-    using iterator = list_type::iterator;
-    using const_iterator = list_type::const_iterator;
-
-private:
-    list_type m_procs;
-    pid_t m_nextpid = 1;
+   private:
+    std::map<pid_t, process> m_procs;
+    pid_t m_nextpid = 2;
 
     constexpr pid_t next_pid() { return m_nextpid++; }
+    process& real_emplace(pid_t pid, pid_t ppid);
 
-public:
-    process& emplace(pid_t ppid)
-    {
-        pid_t pid = next_pid();
-        auto [ iter, inserted ] = m_procs.try_emplace(pid, pid, ppid);
-        assert(inserted);
-
-        if (try_find(ppid)) {
-            bool success = false;
-            std::tie(std::ignore, success) =
-                find(ppid).children.insert(pid);
-            assert(success);
-        }
+   public:
+    proclist();
 
-        return iter->second;
-    }
-
-    process& copy_from(process& proc)
-    {
+    constexpr process& copy_from(process& proc) {
         pid_t pid = next_pid();
-        auto [ iter, inserted ] = m_procs.try_emplace(pid, proc, pid);
+        auto [iter, inserted] = m_procs.try_emplace(pid, proc, pid);
         assert(inserted);
 
         proc.children.insert(pid);
         return iter->second;
     }
 
-    constexpr void remove(pid_t pid)
-    {
+    constexpr void remove(pid_t pid) {
         make_children_orphans(pid);
 
         auto proc_iter = m_procs.find(pid);
@@ -329,25 +115,22 @@ public:
         m_procs.erase(proc_iter);
     }
 
-    constexpr bool try_find(pid_t pid) const
-    { return m_procs.find(pid); }
-
-    // if process doesn't exist, the behavior is undefined
-    constexpr process& find(pid_t pid)
-    {
+    constexpr std::pair<process*, bool> try_find(pid_t pid) const {
         auto iter = m_procs.find(pid);
-        assert(iter);
-        return iter->second;
+        if (iter)
+            return {(process*)&iter->second, true};
+        else
+            return {nullptr, false};
     }
 
-    constexpr bool has_child(pid_t pid)
-    {
-        auto& proc = find(pid);
-        return !proc.children.empty();
+    // if process doesn't exist, the behavior is undefined
+    constexpr process& find(pid_t pid) {
+        auto [ptr, found] = try_find(pid);
+        assert(found);
+        return *ptr;
     }
 
-    constexpr void make_children_orphans(pid_t pid)
-    {
+    constexpr void make_children_orphans(pid_t pid) {
         auto& children = find(pid).children;
         auto& init_children = find(1).children;
 
@@ -360,81 +143,31 @@ public:
     }
 
     // the process MUST exist, or the behavior is undefined
-    void send_signal(pid_t pid, kernel::sig_t signal)
-    {
-        auto& proc = this->find(pid);
-        proc.signals.set(signal);
-    }
-    void send_signal_grp(pid_t pgid, kernel::sig_t signal)
-    {
-        for (auto& [ pid, proc ] : m_procs) {
-            if (proc.pgid == pgid)
-                proc.signals.set(signal);
+    void send_signal(pid_t pid, kernel::signal_list::signo_type signal) {
+        auto& proc = find(pid);
+        proc.send_signal(signal);
+    }
+    void send_signal_grp(pid_t pgid, kernel::signal_list::signo_type signal) {
+        // TODO: find processes that are in the same session quickly
+        for (auto& [pid, proc] : m_procs) {
+            if (proc.pgid != pgid)
+                continue;
+            proc.send_signal(signal);
         }
     }
 
     void kill(pid_t pid, int exit_code);
-};
 
-// TODO: lock and unlock
-class readyqueue final {
-public:
-    using thread = kernel::tasks::thread;
-    using list_type = std::list<thread*>;
-
-private:
-    list_type m_thds;
-
-private:
-    readyqueue(const readyqueue&) = delete;
-    readyqueue(readyqueue&&) = delete;
-    readyqueue& operator=(const readyqueue&) = delete;
-    readyqueue& operator=(readyqueue&&) = delete;
-
-    ~readyqueue() = delete;
-
-public:
-    constexpr explicit readyqueue(void) = default;
-
-    constexpr void push(thread* thd)
-    { m_thds.push_back(thd); }
-
-    constexpr thread* pop(void)
-    {
-        m_thds.remove_if([](thread* item) {
-            return !item->attr.ready;
-        });
-        auto* retval = m_thds.front();
-        m_thds.pop_front();
-        return retval;
-    }
-
-    constexpr thread* query(void)
-    {
-        auto* thd = this->pop();
-        this->push(thd);
-        return thd;
-    }
-
-    constexpr void remove_all(thread* thd)
-    { m_thds.remove(thd); }
+    constexpr auto begin() const { return m_procs.begin(); }
+    constexpr auto end() const { return m_procs.end(); }
 };
 
-void NORETURN init_scheduler(void);
+void NORETURN init_scheduler(kernel::mem::paging::pfn_t kernel_stack_pfn);
 /// @return true if returned normally, false if being interrupted
 bool schedule(void);
 void NORETURN schedule_noreturn(void);
 
-constexpr uint32_t push_stack(uint32_t** stack, uint32_t val)
-{
-    --*stack;
-    **stack = val;
-    return val;
-}
-
-void k_new_thread(void (*func)(void*), void* data);
-
 void NORETURN freeze(void);
-void NORETURN kill_current(int exit_code);
+void NORETURN kill_current(int signo);
 
 void check_signal(void);

+ 47 - 58
include/kernel/signal.hpp

@@ -1,85 +1,74 @@
 #pragma once
 
 #include <list>
+#include <map>
 
+#include <signal.h>
 #include <stdint.h>
+
 #include <types/cplusplus.hpp>
+#include <types/types.h>
+
+#include <kernel/async/lock.hpp>
+#include <kernel/interrupt.hpp>
 
 namespace kernel {
 
-using sig_t = uint32_t;
+using sigmask_type = uint64_t;
 
-constexpr sig_t SIGINT = 2;
-constexpr sig_t SIGQUIT = 3;
-constexpr sig_t SIGSTOP = 13;
-constexpr sig_t SIGPIPE = 19;
+struct sigaction {
+    sighandler_t sa_handler;
+    unsigned long sa_flags;
+    sigrestorer_t sa_restorer;
+    sigmask_type sa_mask;
+};
 
 class signal_list {
-public:
-    using list_type = std::list<sig_t>;
+   public:
+    using signo_type = uint32_t;
+    using list_type = std::list<signo_type>;
 
-private:
+   private:
     list_type m_list;
-    sig_t m_mask;
-
-public:
-    static constexpr bool check_valid(sig_t sig)
-    {
-        switch (sig) {
-        case SIGINT:
-        case SIGQUIT:
-        case SIGSTOP:
-        case SIGPIPE:
-            return true;
-        default:
-            return false;
-        }
-    }
+    sigmask_type m_mask{};
+    std::map<signo_type, sigaction> m_handlers;
+    async::mutex m_mtx;
 
-public:
-    constexpr signal_list(void)
-        : m_mask(0)
-    {
+   public:
+    static constexpr bool check_valid(signo_type sig) {
+        return sig >= 1 && sig <= 64;
     }
+
+   public:
+    constexpr signal_list() = default;
     constexpr signal_list(const signal_list& val)
-        : m_list(val.m_list)
-        , m_mask(val.m_mask)
-    {
-    }
+        : m_list{val.m_list}
+        , m_mask{val.m_mask}
+        , m_handlers{val.m_handlers}
+        , m_mtx{} {}
 
     constexpr signal_list(signal_list&& val)
-        : m_list(std::move(val.m_list))
-        , m_mask(val.m_mask)
-    {
-    }
-
-    constexpr bool empty(void) const
-    {
-        return this->m_list.empty();
-    }
+        : m_list{std::move(val.m_list)}
+        , m_mask{std::move(val.m_mask)}
+        , m_handlers{std::move(val.m_handlers)}
+        , m_mtx{} {}
 
-    constexpr void set(sig_t signal)
-    {
-        if (this->m_mask && signal)
-            return;
+    void on_exec();
 
-        this->m_list.push_back(signal);
-        this->m_mask |= signal;
-    }
-
-    constexpr sig_t pop(void)
-    {
-        if (this->empty())
-            return 0;
+    sigmask_type get_mask() const;
+    void set_mask(sigmask_type mask);
+    void mask(sigmask_type mask);
+    void unmask(sigmask_type mask);
 
-        auto iter = this->m_list.begin();
-        sig_t signal = *iter;
-        this->m_list.erase(iter);
+    void set_handler(signo_type signal, const sigaction& action);
+    void get_handler(signo_type signal, sigaction& action) const;
 
-        this->m_mask &= ~signal;
+    signo_type pending_signal();
 
-        return signal;
-    }
+    // return value: whether the thread should wake up
+    bool raise(signo_type signal);
+    void handle(interrupt_stack* context, mmx_registers* mmxregs);
+    void after_signal(signo_type signal);
 };
 
 } // namespace kernel

+ 113 - 4
include/kernel/syscall.hpp

@@ -1,9 +1,118 @@
 #pragma once
 
-#include <kernel/interrupt.h>
+#include <string>
+#include <vector>
+
+#include <bits/alltypes.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+#include <time.h>
+
 #include <types/types.h>
 
-// return value is stored in %eax and %edx
-typedef int (*syscall_handler)(interrupt_stack* data);
+#include <kernel/interrupt.hpp>
+#include <kernel/signal.hpp>
+#include <kernel/user/thread_local.hpp>
+
+#define SYSCALL64_ARG1(type, name) type name = (type)((data)->head.s_regs.rdi)
+#define SYSCALL64_ARG2(type, name) type name = (type)((data)->head.s_regs.rsi)
+#define SYSCALL64_ARG3(type, name) type name = (type)((data)->head.s_regs.rdx)
+#define SYSCALL64_ARG4(type, name) type name = (type)((data)->head.s_regs.r10)
+#define SYSCALL64_ARG5(type, name) type name = (type)((data)->head.s_regs.r8)
+#define SYSCALL64_ARG6(type, name) type name = (type)((data)->head.s_regs.r9)
+
+namespace kernel {
+void init_syscall_table();
+
+void handle_syscall32(int no, interrupt_stack* data, mmx_registers* mmxregs);
+void handle_syscall64(int no, interrupt_stack* data, mmx_registers* mmxregs);
+
+namespace syscall {
+    // in fileops.cc
+    ssize_t do_write(int fd, const char __user* buf, size_t n);
+    ssize_t do_read(int fd, char __user* buf, size_t n);
+    int do_close(int fd);
+    int do_dup(int old_fd);
+    int do_dup2(int old_fd, int new_fd);
+    int do_pipe(int __user* pipefd);
+    ssize_t do_getdents(int fd, char __user* buf, size_t cnt);
+    ssize_t do_getdents64(int fd, char __user* buf, size_t cnt);
+    int do_open(const char __user* path, int flags, mode_t mode);
+    int do_symlink(const char __user* target, const char __user* linkpath);
+    int do_readlink(const char __user* pathname, char __user* buf,
+                    size_t buf_size);
+    int do_ioctl(int fd, unsigned long request, uintptr_t arg3);
+    ssize_t do_readv(int fd, const iovec* iov, int iovcnt);
+    ssize_t do_writev(int fd, const iovec* iov, int iovcnt);
+    off_t do_lseek(int fd, off_t offset, int whence);
+    uintptr_t do_mmap_pgoff(uintptr_t addr, size_t len, int prot, int flags,
+                            int fd, off_t pgoffset);
+    int do_munmap(uintptr_t addr, size_t len);
+    ssize_t do_sendfile(int out_fd, int in_fd, off_t __user* offset,
+                        size_t count);
+    int do_statx(int dirfd, const char __user* path, int flags,
+                 unsigned int mask, statx __user* statxbuf);
+    int do_fcntl(int fd, int cmd, unsigned long arg);
+    int do_poll(pollfd __user* fds, nfds_t nfds, int timeout);
+    int do_mknod(const char __user* pathname, mode_t mode, dev_t dev);
+    int do_access(const char __user* pathname, int mode);
+    int do_unlink(const char __user* pathname);
+    int do_truncate(const char __user* pathname, long length);
+    int do_mkdir(const char __user* pathname, mode_t mode);
+    int do_socket(int domain, int type, int protocol);
+
+    // in procops.cc
+    int do_chdir(const char __user* path);
+    [[noreturn]] int do_exit(int status);
+    int do_waitpid(pid_t waitpid, int __user* arg1, int options);
+    pid_t do_getsid(pid_t pid);
+    pid_t do_setsid();
+    pid_t do_getpgid(pid_t pid);
+    int do_setpgid(pid_t pid, pid_t pgid);
+    int do_set_thread_area(user::user_desc __user* ptr);
+    pid_t do_set_tid_address(int __user* tidptr);
+    int do_prctl(int option, uintptr_t arg2);
+    int do_arch_prctl(int option, uintptr_t arg2);
+    pid_t do_getpid();
+    pid_t do_getppid();
+    uid_t do_getuid();
+    uid_t do_geteuid();
+    gid_t do_getgid();
+    pid_t do_gettid();
+    int do_getcwd(char __user* buf, size_t buf_size);
+    uintptr_t do_brk(uintptr_t addr);
+    int do_umask(mode_t mask);
+    int do_kill(pid_t pid, int sig);
+    int do_tkill(pid_t pid, int sig);
+    int do_rt_sigprocmask(int how, const kernel::sigmask_type __user* set,
+                          kernel::sigmask_type __user* oldset,
+                          size_t sigsetsize);
+    int do_rt_sigaction(int signum, const sigaction __user* act,
+                        sigaction __user* oldact, size_t sigsetsize);
+    int do_newuname(new_utsname __user* buf);
+
+    struct execve_retval {
+        uintptr_t ip;
+        uintptr_t sp;
+        int status;
+    };
+
+    execve_retval do_execve(const std::string& exec,
+                            const std::vector<std::string>& args,
+                            const std::vector<std::string>& envs);
+
+    // in mount.cc
+    int do_mount(const char __user* source, const char __user* target,
+                 const char __user* fstype, unsigned long flags,
+                 const void __user* _fsdata);
+
+    // in infoops.cc
+    int do_clock_gettime(clockid_t clk_id, timespec __user* tp);
+    int do_gettimeofday(timeval __user* tv, void __user* tz);
+
+} // namespace syscall
 
-void init_syscall(void);
+} // namespace kernel

+ 0 - 18
include/kernel/task.h

@@ -1,18 +0,0 @@
-#pragma once
-
-#include <types/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct tss32_t {
-    uint32_t backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
-    uint32_t eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
-    uint32_t es, cs, ss, ds, fs, gs;
-    uint32_t ldtr, iomap;
-};
-
-#ifdef __cplusplus
-}
-#endif

+ 5 - 0
include/kernel/task/current.hpp

@@ -0,0 +1,5 @@
+#pragma once
+
+#include <kernel/task/thread.hpp>
+
+inline kernel::task::thread* volatile current_thread;

+ 7 - 0
include/kernel/task/forward.hpp

@@ -0,0 +1,7 @@
+#pragma once
+
+namespace kernel::task {
+
+class thread;
+
+} // namespace kernel::task

+ 16 - 0
include/kernel/task/readyqueue.hpp

@@ -0,0 +1,16 @@
+#pragma once
+
+#include <list>
+
+#include <kernel/task/thread.hpp>
+
+namespace kernel::task::dispatcher {
+
+void enqueue(thread* thd);
+void dequeue(thread* thd);
+
+void setup_idle(thread* idle_thd);
+
+thread* next();
+
+} // namespace kernel::task::dispatcher

+ 76 - 0
include/kernel/task/thread.hpp

@@ -0,0 +1,76 @@
+#pragma once
+
+#include <cstddef>
+#include <string>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <types/types.h>
+
+#include <kernel/mem/paging.hpp>
+#include <kernel/signal.hpp>
+#include <kernel/user/thread_local.hpp>
+
+namespace kernel::task {
+
+using tid_t = std::size_t;
+
+struct thread {
+   public:
+    using thd_attr_t = uint32_t;
+    static constexpr thd_attr_t SYSTEM = 0x01;
+    static constexpr thd_attr_t READY = 0x02;
+    static constexpr thd_attr_t STOPPED = 0x04;
+    static constexpr thd_attr_t ZOMBIE = 0x08;
+    static constexpr thd_attr_t ISLEEP = 0x10;
+    static constexpr thd_attr_t USLEEP = 0x20;
+
+   private:
+    struct kernel_stack {
+        mem::paging::pfn_t pfn;
+        uintptr_t sp;
+
+        kernel_stack();
+        kernel_stack(const kernel_stack& other);
+        kernel_stack(kernel_stack&& other);
+        ~kernel_stack();
+
+        uint64_t pushq(uint64_t val);
+        uint32_t pushl(uint32_t val);
+
+        void load_interrupt_stack() const;
+    };
+
+   public:
+    kernel_stack kstack;
+    pid_t owner;
+    thd_attr_t attr;
+    signal_list signals;
+
+    int* __user set_child_tid{};
+    int* __user clear_child_tid{};
+
+    std::string name{};
+    uint64_t tls_desc32{};
+    std::size_t elected_times{};
+
+    explicit thread(std::string name, pid_t owner);
+    thread(const thread& val, pid_t owner);
+
+    int set_thread_area(user::user_desc* ptr);
+    int load_thread_area32() const;
+
+    void set_attr(thd_attr_t new_attr);
+
+    void send_signal(signal_list::signo_type signal);
+
+    thread(thread&& val) = default;
+
+    tid_t tid() const;
+
+    bool operator<(const thread& rhs) const;
+    bool operator==(const thread& rhs) const;
+};
+
+} // namespace kernel::task

+ 44 - 31
include/kernel/tty.hpp

@@ -1,60 +1,73 @@
 #pragma once
-#include <kernel/event/evtqueue.hpp>
+
+#include <string>
+
 #include <stdint.h>
 #include <sys/types.h>
+#include <termios.h>
+
 #include <types/allocator.hpp>
 #include <types/buffer.hpp>
 #include <types/cplusplus.hpp>
 
+#include <kernel/async/lock.hpp>
+#include <kernel/async/waitlist.hpp>
+
+namespace kernel::tty {
+
 class tty : public types::non_copyable {
-public:
+   public:
     static constexpr size_t BUFFER_SIZE = 4096;
-    static constexpr size_t NAME_SIZE = 32;
 
-public:
-    tty();
+   private:
+    void _real_commit_char(int c);
+    void _echo_char(int c);
+
+    int _do_erase(bool should_echo);
+
+   public:
+    explicit tty(std::string name);
     virtual void putchar(char c) = 0;
-    virtual void recvchar(char c) = 0;
     void print(const char* str);
-    size_t read(char* buf, size_t buf_size, size_t n);
+    ssize_t read(char* buf, size_t buf_size, size_t n);
+    ssize_t write(const char* buf, size_t n);
+
+    // characters committed to buffer will be handled
+    // by the input line discipline (N_TTY)
+    void commit_char(int c);
+
+    // print character to the output
+    // characters will be handled by the output line discipline
+    void show_char(int c);
 
     void clear_read_buf(void);
 
-    constexpr void set_pgrp(pid_t pgid)
-    {
-        fg_pgroup = pgid;
-    }
+    // TODO: formal poll support
+    int poll();
 
-    constexpr pid_t get_pgrp(void) const
-    {
-        return fg_pgroup;
-    }
+    constexpr void set_pgrp(pid_t pgid) { fg_pgroup = pgid; }
 
-    char name[NAME_SIZE];
-    bool echo = true;
+    constexpr pid_t get_pgrp(void) const { return fg_pgroup; }
 
-protected:
-    types::buffer<types::kernel_ident_allocator> buf;
-    kernel::cond_var m_cv;
+    termios termio;
+    std::string name;
+
+   protected:
+    async::mutex mtx_buf;
+    types::buffer buf;
+    async::wait_list waitlist;
 
     pid_t fg_pgroup;
 };
 
 class vga_tty : public virtual tty {
-public:
+   public:
     vga_tty();
     virtual void putchar(char c) override;
-    virtual void recvchar(char c) override;
 };
 
-class serial_tty : public virtual tty {
-public:
-    serial_tty(int id);
-    virtual void putchar(char c) override;
-    virtual void recvchar(char c) override;
+inline tty* console;
 
-public:
-    uint16_t id;
-};
+int register_tty(tty* tty_dev);
 
-inline tty* console;
+} // namespace kernel::tty

+ 1 - 1
include/kernel/user/thread_local.hpp

@@ -16,6 +16,6 @@ struct user_desc {
     uint32_t useable : 1;
 };
 
-int set_thread_area(user_desc* ptr);
+void load_thread_area32(uint64_t desc);
 
 } // namespace kernel::user

+ 9 - 0
include/kernel/utsname.hpp

@@ -0,0 +1,9 @@
+#pragma once
+
+#include <sys/utsname.h>
+
+namespace kernel {
+
+inline new_utsname* sys_utsname;
+
+} // namespace kernel

+ 62 - 313
include/kernel/vfs.hpp

@@ -1,81 +1,25 @@
 #pragma once
 
-#include <map>
-#include <list>
-#include <vector>
-#include <functional>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
 #include <bits/alltypes.h>
-
-#include <assert.h>
-#include <kernel/event/evtqueue.hpp>
 #include <stdint.h>
+#include <sys/stat.h>
 #include <sys/types.h>
-#include <types/allocator.hpp>
-#include <types/buffer.hpp>
-#include <types/cplusplus.hpp>
-#include <types/hash_map.hpp>
-#include <types/path.hpp>
-#include <types/lock.hpp>
-#include <types/types.h>
 
-#define INODE_FILE (1 << 0)
-#define INODE_DIR (1 << 1)
-#define INODE_MNT (1 << 2)
-#define INODE_NODE (1 << 3)
+#include <types/path.hpp>
 
-// dirent file types
-#define DT_UNKNOWN 0
-#define DT_FIFO 1
-#define DT_CHR 2
-#define DT_DIR 4
-#define DT_BLK 6
-#define DT_REG 8
-#define DT_LNK 10
-#define DT_SOCK 12
-#define DT_WHT 14
+#include <kernel/mem/paging.hpp>
+#include <kernel/vfs/dentry.hpp>
+#include <kernel/vfs/file.hpp>
 
-#define DT_MAX (S_DT_MASK + 1) /* 16 */
+#define NODE_MAJOR(node) (((node) >> 8) & 0xFFU)
+#define NODE_MINOR(node) ((node) & 0xFFU)
 
 namespace fs {
-using blksize_t = size_t;
-using blkcnt_t = size_t;
-
-class vfs;
-
-struct inode {
-    ino_t ino;
-    vfs* fs;
-    size_t size;
 
-    mode_t mode;
-    uid_t uid;
-    gid_t gid;
-};
-
-#define NODE_MAJOR(node) ((node) >> 16)
-#define NODE_MINOR(node) ((node) & 0xffff)
-constexpr dev_t NODE_INVALID = -1U;
-
-constexpr dev_t make_device(uint32_t major, uint32_t minor)
-{
-    return (major << 16) | (minor & 0xffff);
+constexpr dev_t make_device(uint32_t major, uint32_t minor) {
+    return ((major << 8) & 0xFF00U) | (minor & 0xFFU);
 }
 
-// buf, buf_size, offset, cnt
-using blkdev_read = std::function<ssize_t(char*, std::size_t, std::size_t, std::size_t)>;
-
-// buf, offset, cnt
-using blkdev_write = std::function<ssize_t(const char*, std::size_t, std::size_t)>;
-
-struct blkdev_ops {
-    blkdev_read read;
-    blkdev_write write;
-};
-
 // buf, buf_size, cnt
 using chrdev_read = std::function<ssize_t(char*, std::size_t, std::size_t)>;
 
@@ -88,265 +32,70 @@ struct chrdev_ops {
 };
 
 struct PACKED user_dirent {
-    ino_t d_ino; // inode number
-    uint32_t d_off; // ignored
+    ino_t d_ino;       // inode number
+    uint32_t d_off;    // ignored
     uint16_t d_reclen; // length of this struct user_dirent
-    char d_name[1]; // file name with a padding zero
+    char d_name[1];    // file name with a padding zero
     // uint8_t d_type; // file type, with offset of (d_reclen - 1)
 };
 
-struct user_dirent64 {
-    ino64_t d_ino; // inode number
-    uint64_t d_off; // implementation-defined field, ignored
+struct PACKED user_dirent64 {
+    ino64_t d_ino;     // inode number
+    uint64_t d_off;    // implementation-defined field, ignored
     uint16_t d_reclen; // length of this struct user_dirent
-    uint8_t d_type; // file type, with offset of (d_reclen - 1)
-    char d_name[1]; // file name with a padding zero
+    uint8_t d_type;    // file type, with offset of (d_reclen - 1)
+    char d_name[1];    // file name with a padding zero
 };
 
-class vfs {
-public:
-    struct dentry {
-    public:
-        using name_type = types::string<>;
-        template <typename T>
-        using allocator_type = types::kernel_allocator<T>;
-
-    private:
-        std::list<dentry, types::allocator_adapter<dentry, allocator_type>>* children = nullptr;
-        types::hash_map<name_type, dentry*, types::linux_hasher, allocator_type>* idx_children = nullptr;
-
-    public:
-        dentry* parent;
-        inode* ind;
-        // if the entry is a file, this flag is ignored
-        union {
-            uint32_t v;
-            struct {
-                uint32_t present : 1;
-                uint32_t dirty : 1;
-            } in;
-        } flags;
-        name_type name;
-
-        explicit dentry(dentry* parent, inode* ind, name_type name);
-        dentry(const dentry& val) = delete;
-        constexpr dentry(dentry&& val)
-            : children(std::exchange(val.children, nullptr))
-            , idx_children(std::exchange(val.idx_children, nullptr))
-            , parent(std::exchange(val.parent, nullptr))
-            , ind(std::exchange(val.ind, nullptr))
-            , flags { val.flags }
-            , name(std::move(val.name))
-        {
-            if (children) {
-                for (auto& item : *children)
-                    item.parent = this;
-            }
-        }
-
-        dentry& operator=(const dentry& val) = delete;
-        dentry& operator=(dentry&& val) = delete;
-
-        constexpr ~dentry()
-        {
-            if (children) {
-                types::pdelete<allocator_type>(children);
-                children = nullptr;
-            }
-            if (idx_children) {
-                types::pdelete<allocator_type>(idx_children);
-                idx_children = nullptr;
-            }
-        }
-
-        dentry* append(inode* ind, const name_type& name, bool set_dirty);
-        dentry* append(inode* ind, name_type&& name, bool set_dirty);
-
-        dentry* find(const name_type& name);
-
-        dentry* replace(dentry* val);
-
-        // out_dst SHOULD be empty
-        void path(const dentry& root, types::path& out_dst) const;
-
-        void invalidate(void);
-    };
-
-public:
-    using filldir_func = std::function<int(const char*, size_t, ino_t, uint8_t)>;
-
-private:
-    // TODO: use allocator designed for small objects
-    using inode_list = std::map<ino_t, inode>;
-
-private:
-    inode_list _inodes;
-    types::hash_map<dentry*, dentry*> _mount_recover_list;
-
-protected:
-    dentry _root;
-
-protected:
-    inode* cache_inode(size_t size, ino_t ino, mode_t mode, uid_t uid, gid_t gid);
-    inode* get_inode(ino_t ino);
-    void register_root_node(inode* root);
-
-    int load_dentry(dentry* ent);
-
-public:
-    explicit vfs(void);
-    vfs(const vfs&) = delete;
-    vfs& operator=(const vfs&) = delete;
-    vfs(vfs&&) = delete;
-    vfs& operator=(vfs&&) = delete;
-
-    constexpr dentry* root(void)
-    {
-        return &_root;
-    }
-
-    int mount(dentry* mnt, vfs* new_fs);
-
-    virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
-    virtual size_t inode_write(inode* file, const char* buf, size_t offset, size_t n);
-    virtual int inode_mkfile(dentry* dir, const char* filename, mode_t mode);
-    virtual int inode_mknode(dentry* dir, const char* filename, mode_t mode, dev_t sn);
-    virtual int inode_rmfile(dentry* dir, const char* filename);
-    virtual int inode_mkdir(dentry* dir, const char* dirname);
-    virtual int inode_statx(dentry* dent, statx* buf, unsigned int mask);
-    virtual int inode_stat(dentry* dent, struct stat* stat);
-    virtual dev_t inode_devid(inode* file);
-
-    // parameter 'length' in callback:
-    // if 0, 'name' should be null terminated
-    // else, 'name' size
-    //
-    // @return
-    // return -1 if an error occurred
-    // return 0 if no more entry available
-    // otherwise, return bytes to be added to the offset
-    virtual int inode_readdir(inode* dir, size_t offset, const filldir_func& callback) = 0;
+struct fs_context {
+    dentry_pointer root;
 };
 
-class pipe : public types::non_copyable {
-private:
-    static constexpr size_t PIPE_SIZE = 4096;
-    static constexpr uint32_t READABLE = 1;
-    static constexpr uint32_t WRITABLE = 2;
-
-private:
-    types::buffer<types::kernel_allocator> buf;
-    kernel::cond_var m_cv;
-    uint32_t flags;
-
-public:
-    pipe(void);
-
-    void close_read(void);
-    void close_write(void);
-
-    int write(const char* buf, size_t n);
-    int read(char* buf, size_t n);
-
-    constexpr bool is_readable(void) const
-    {
-        return flags & READABLE;
-    }
-
-    constexpr bool is_writeable(void) const
-    {
-        return flags & WRITABLE;
-    }
-
-    constexpr bool is_free(void) const
-    {
-        return !(flags & (READABLE | WRITABLE));
-    }
-};
-
-struct file {
-    mode_t mode; // stores the file type in the same format as inode::mode
-    vfs::dentry* parent {};
-    struct file_flags {
-        uint32_t read : 1;
-        uint32_t write : 1;
-        uint32_t close_on_exec : 1;
-    } flags {};
-
-    file(mode_t mode, vfs::dentry* parent, file_flags flags)
-        : mode(mode) , parent(parent), flags(flags) { }
-
-    virtual ~file() = default;
-
-    virtual ssize_t read(char* __user buf, size_t n) = 0;
-    virtual ssize_t write(const char* __user buf, size_t n) = 0;
-    virtual void close() = 0;
-
-    // regular files should override this method
-    virtual int getdents(char* __user buf, size_t cnt)
-    { return (void)buf, (void)cnt, -ENOTDIR; }
-    virtual int getdents64(char* __user buf, size_t cnt)
-    { return (void)buf, (void)cnt, -ENOTDIR; }
-};
-
-struct regular_file : public virtual file {
-    virtual ~regular_file() = default;
-    std::size_t cursor { };
-    inode* ind { };
-
-    regular_file(vfs::dentry* parent, file_flags flags, size_t cursor, inode* ind);
-
-    virtual ssize_t read(char* __user buf, size_t n) override;
-    virtual ssize_t write(const char* __user buf, size_t n) override;
-    virtual void close() override;
-    virtual int getdents(char* __user buf, size_t cnt) override;
-    virtual int getdents64(char* __user buf, size_t cnt) override;
-};
-
-struct fifo_file : public virtual file {
-    virtual ~fifo_file() = default;
-    std::shared_ptr<pipe> ppipe;
-
-    fifo_file(vfs::dentry* parent, file_flags flags, std::shared_ptr<fs::pipe> ppipe);
-
-    virtual ssize_t read(char* __user buf, size_t n) override;
-    virtual ssize_t write(const char* __user buf, size_t n) override;
-    virtual void close() override;
-};
-
-inline fs::vfs::dentry* fs_root;
-
-int register_block_device(dev_t node, blkdev_ops ops);
-int register_char_device(dev_t node, chrdev_ops ops);
-
-void partprobe();
-
-ssize_t block_device_read(dev_t node, char* buf, size_t buf_size, size_t offset, size_t n);
-ssize_t block_device_write(dev_t node, const char* buf, size_t offset, size_t n);
-
+int register_char_device(dev_t node, const chrdev_ops& ops);
 ssize_t char_device_read(dev_t node, char* buf, size_t buf_size, size_t n);
 ssize_t char_device_write(dev_t node, const char* buf, size_t n);
 
-vfs* register_fs(vfs* fs);
-
-size_t vfs_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
-size_t vfs_write(inode* file, const char* buf, size_t offset, size_t n);
-int vfs_mkfile(fs::vfs::dentry* dir, const char* filename, mode_t mode);
-int vfs_mknode(fs::vfs::dentry* dir, const char* filename, mode_t mode, dev_t sn);
-int vfs_rmfile(fs::vfs::dentry* dir, const char* filename);
-int vfs_mkdir(fs::vfs::dentry* dir, const char* dirname);
-int vfs_stat(fs::vfs::dentry* dent, statx* stat, unsigned int mask);
-
-/**
- * @brief Opens a file or directory specified by the given path.
- * 
- * @param root The root directory of the file system.
- * @param path The absolute path to the file or directory to be opened.
- * @return A pointer to the opened file or directory entry if found.
- *         Otherwise, nullptr is returned.
- */
-fs::vfs::dentry* vfs_open(fs::vfs::dentry& root, const types::path& path);
+extern "C" int fs_creat(struct dentry* at, mode_t mode);
+extern "C" int fs_mkdir(struct dentry* at, mode_t mode);
+extern "C" int fs_mknod(struct dentry* at, mode_t mode, dev_t sn);
+extern "C" int fs_unlink(struct dentry* at);
+extern "C" int fs_symlink(struct dentry* at, const char* target);
+
+extern "C" int fs_statx(const struct rust_inode_handle* inode,
+                        struct statx* stat, unsigned int mask);
+extern "C" int fs_readlink(const struct rust_inode_handle* inode, char* buf,
+                           size_t buf_size);
+extern "C" int fs_truncate(const struct rust_inode_handle* file, size_t size);
+extern "C" size_t fs_read(const struct rust_inode_handle* file, char* buf,
+                          size_t buf_size, size_t offset, size_t n);
+extern "C" size_t fs_write(const struct rust_inode_handle* file,
+                           const char* buf, size_t offset, size_t n);
+
+using readdir_callback_fn = std::function<int(const char*, size_t, ino_t)>;
+
+extern "C" ssize_t fs_readdir(const struct rust_inode_handle* file,
+                              size_t offset,
+                              const readdir_callback_fn* callback);
+
+extern "C" int fs_mount(dentry* mnt, const char* source,
+                        const char* mount_point, const char* fstype,
+                        unsigned long flags, const void* data);
+
+extern "C" mode_t r_get_inode_mode(struct rust_inode_handle* inode);
+extern "C" size_t r_get_inode_size(struct rust_inode_handle* inode);
+extern "C" bool r_dentry_is_directory(struct dentry* dentry);
+extern "C" bool r_dentry_is_invalid(struct dentry* dentry);
+
+// borrow from dentry->inode
+extern "C" struct rust_inode_handle* r_dentry_get_inode(struct dentry* dentry);
+extern "C" struct dentry* r_get_root_dentry();
+
+#define current_open(...) \
+    fs::open(current_process->fs_context, current_process->cwd, __VA_ARGS__)
+
+std::pair<dentry_pointer, int> open(const fs_context& context,
+                                    const dentry_pointer& cwd,
+                                    types::string_view path,
+                                    bool follow_symlinks = true);
 
 } // namespace fs
-
-extern "C" void init_vfs(void);

+ 28 - 0
include/kernel/vfs/dentry.hpp

@@ -0,0 +1,28 @@
+#pragma once
+
+#include <string>
+
+#include <bits/alltypes.h>
+
+#include <types/path.hpp>
+
+#include <kernel/async/lock.hpp>
+
+struct dentry;
+
+namespace fs {
+
+struct rust_vfs_handle {
+    void* data[2];
+};
+
+struct dentry_deleter {
+    void operator()(struct dentry* dentry) const;
+};
+
+using dentry_pointer = std::unique_ptr<struct dentry, dentry_deleter>;
+extern "C" int d_path(struct dentry* dentry, struct dentry* root,
+                      char* out_path, size_t buflen);
+dentry_pointer d_get(const dentry_pointer& dp);
+
+} // namespace fs

+ 106 - 0
include/kernel/vfs/file.hpp

@@ -0,0 +1,106 @@
+#pragma once
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <types/buffer.hpp>
+#include <types/types.h>
+
+#include <kernel/async/lock.hpp>
+#include <kernel/async/waitlist.hpp>
+#include <kernel/vfs/dentry.hpp>
+
+namespace fs {
+
+class pipe : public types::non_copyable {
+   private:
+    static constexpr size_t PIPE_SIZE = 4096;
+    static constexpr uint32_t READABLE = 1;
+    static constexpr uint32_t WRITABLE = 2;
+
+   private:
+    types::buffer buf;
+    uint32_t flags;
+    kernel::async::mutex mtx;
+
+    kernel::async::wait_list waitlist_r;
+    kernel::async::wait_list waitlist_w;
+
+   public:
+    pipe();
+
+    void close_read();
+    void close_write();
+
+    int write(const char* buf, size_t n);
+    int read(char* buf, size_t n);
+
+    constexpr bool is_readable() const { return flags & READABLE; }
+
+    constexpr bool is_writeable() const { return flags & WRITABLE; }
+};
+
+struct file {
+    struct file_flags {
+        uint32_t read : 1;
+        uint32_t write : 1;
+        uint32_t append : 1;
+    } flags{};
+
+    file(file_flags flags) : flags(flags) {}
+
+    virtual ~file() = default;
+
+    virtual ssize_t read(char* __user buf, size_t n) = 0;
+    virtual ssize_t do_write(const char* __user buf, size_t n) = 0;
+
+    virtual off_t seek(off_t n, int whence) {
+        return (void)n, (void)whence, -ESPIPE;
+    }
+
+    ssize_t write(const char* __user buf, size_t n) {
+        if (!flags.write)
+            return -EBADF;
+
+        if (flags.append) {
+            seek(0, SEEK_END);
+        }
+
+        return do_write(buf, n);
+    }
+
+    // regular files should override this method
+    virtual int getdents(char* __user buf, size_t cnt) {
+        return (void)buf, (void)cnt, -ENOTDIR;
+    }
+    virtual int getdents64(char* __user buf, size_t cnt) {
+        return (void)buf, (void)cnt, -ENOTDIR;
+    }
+};
+
+struct regular_file : public virtual file {
+    virtual ~regular_file() = default;
+    std::size_t cursor{};
+    struct rust_inode_handle* ind{};
+
+    regular_file(file_flags flags, size_t cursor, rust_inode_handle* ind);
+
+    virtual ssize_t read(char* __user buf, size_t n) override;
+    virtual ssize_t do_write(const char* __user buf, size_t n) override;
+    virtual off_t seek(off_t n, int whence) override;
+    virtual int getdents(char* __user buf, size_t cnt) override;
+    virtual int getdents64(char* __user buf, size_t cnt) override;
+};
+
+struct fifo_file : public virtual file {
+    virtual ~fifo_file() override;
+    std::shared_ptr<pipe> ppipe;
+
+    fifo_file(file_flags flags, std::shared_ptr<fs::pipe> ppipe);
+
+    virtual ssize_t read(char* __user buf, size_t n) override;
+    virtual ssize_t do_write(const char* __user buf, size_t n) override;
+};
+
+} // namespace fs

+ 51 - 0
include/kernel/vfs/filearr.hpp

@@ -0,0 +1,51 @@
+#pragma once
+
+#include "dentry.hpp"
+#include "file.hpp"
+
+#include <memory>
+
+#include <types/path.hpp>
+
+#include <kernel/vfs.hpp>
+
+namespace fs {
+
+class filearray {
+   private:
+    struct impl;
+    std::shared_ptr<impl> pimpl;
+    filearray(std::shared_ptr<impl>);
+
+   public:
+    filearray(const fs_context* ctx);
+    filearray(filearray&& other) = default;
+
+    filearray copy() const;
+    filearray share() const;
+
+    // dup old_fd to some random fd
+    int dup(int old_fd);
+
+    // dup old_fd to new_fd, close new_fd if it is already open
+    int dup(int old_fd, int new_fd, int flags);
+
+    // dup old_fd to the first available fd starting from min_fd
+    int dupfd(int fd, int min_fd, int flags);
+
+    fs::file* operator[](int i) const;
+    int set_flags(int fd, int flags);
+
+    int pipe(int (&pipefd)[2]);
+    int open(const dentry_pointer& cwd, types::string_view filepath, int flags,
+             mode_t mode);
+    int open(types::string_view filepath, int flags, mode_t mode);
+
+    int close(int fd);
+
+    // any call to member methods will be invalid after clear()
+    void clear();
+    void onexec();
+};
+
+} // namespace fs

+ 25 - 0
include/kernel/vfs/vfsfwd.hpp

@@ -0,0 +1,25 @@
+#pragma once
+
+namespace fs {
+
+// in dentry.hpp
+struct dcache;
+struct dentry;
+
+// in file.hpp
+struct file;
+struct regular_file;
+struct fifo_file;
+
+class pipe;
+
+// in filearray.hpp
+class file_array;
+
+// in inode.hpp
+struct inode;
+
+// in vfs.hpp
+class vfs;
+
+} // namespace fs

+ 22 - 0
include/net/arp.hpp

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <defs.hpp>
+
+#include <net/ethernet.hpp>
+
+namespace net {
+
+struct PACKED ARPFrame {
+    u16 l2Type;
+    u16 protoType;
+    u8 l2AddrLen;
+    u8 protoAddrLen;
+    u16 op;
+
+    MACAddress srcMAC;
+    u32 srcIP;
+    MACAddress dstMAC;
+    u32 dstIP;
+};
+
+} // namespace net

+ 22 - 0
include/net/ethernet.hpp

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <defs.hpp>
+
+namespace net {
+
+u16 htons(u16 val);
+u32 htonl(u32 val);
+u64 htonll(u64 val);
+
+struct PACKED MACAddress {
+    u8 addr[6];
+};
+
+struct PACKED EthernetHeader {
+    MACAddress dst;
+    MACAddress src;
+    u16 type;
+    u8 payload[];
+};
+
+} // namespace net

+ 42 - 0
include/net/netdev.hpp

@@ -0,0 +1,42 @@
+#pragma once
+
+#include <defs.hpp>
+#include <functional>
+
+#include <stdint.h>
+
+#include <kernel/hw/pci.hpp>
+#include <net/ethernet.hpp>
+
+namespace net {
+
+constexpr unsigned long NETDEV_UP = 0x001;
+constexpr unsigned long NETDEV_DOWN = 0x002;
+
+constexpr unsigned long NETDEV_SPEED_MASK = 0x03c;
+constexpr unsigned long NETDEV_SPEED_UNKNOWN = 0x004;
+constexpr unsigned long NETDEV_SPEED_10M = 0x008;
+constexpr unsigned long NETDEV_SPEED_100M = 0x010;
+constexpr unsigned long NETDEV_SPEED_1000M = 0x020;
+
+class Netdev {
+   protected:
+    unsigned long status;
+    MACAddress mac;
+
+    Netdev(kernel::hw::pci::pci_device& device);
+
+   public:
+    kernel::hw::pci::pci_device& device;
+
+    virtual ~Netdev() = default;
+
+    int setLinkSpeed(unsigned long speedFlag);
+
+    virtual int up() = 0;
+    virtual isize send(const u8* data, usize len) = 0;
+};
+
+int registerNetdev(std::unique_ptr<Netdev> dev);
+
+} // namespace net

+ 30 - 315
include/types/allocator.hpp

@@ -1,334 +1,49 @@
 #pragma once
+#include <cstddef>
+#include <memory>
 #include <new>
-#include <utility>
 #include <type_traits>
-#include <bit>
+#include <utility>
+
 #include <stdint.h>
+
 #include <types/cplusplus.hpp>
 #include <types/types.h>
 
-namespace types {
-
-namespace __allocator {
-    class brk_memory_allocator {
-    public:
-        using byte = uint8_t;
-        using size_type = size_t;
-
-        struct mem_blk_flags {
-            uint8_t is_free;
-            uint8_t has_next;
-            uint8_t _unused2;
-            uint8_t _unused3;
-        };
-
-        struct mem_blk {
-            size_t size;
-            struct mem_blk_flags flags;
-            // the first byte of the memory space
-            // the minimal allocated space is 8 bytes
-            byte data[];
-        };
-
-    private:
-        byte* p_start;
-        byte* p_break;
-        byte* p_limit;
-
-        brk_memory_allocator() = delete;
-        brk_memory_allocator(const brk_memory_allocator&) = delete;
-        brk_memory_allocator(brk_memory_allocator&&) = delete;
-
-        constexpr byte* brk(byte* addr)
-        {
-            if (unlikely(addr >= p_limit))
-                return nullptr;
-            return p_break = addr;
-        }
-
-        constexpr byte* sbrk(size_type increment)
-        { return brk(p_break + increment); }
-
-        constexpr mem_blk* _next(mem_blk* blk, size_type blk_size)
-        {
-            auto* p = std::bit_cast<byte*>(blk);
-            p += sizeof(mem_blk);
-            p += blk_size;
-            return std::bit_cast<mem_blk*>(p);
-        }
-
-        // blk MUST be free
-        constexpr void unite_afterwards(mem_blk* blk)
-        {
-            while (blk->flags.has_next) {
-                auto* blk_next = _next(blk, blk->size);
-                if (!blk_next->flags.is_free)
-                    break;
-                blk->size += sizeof(mem_blk) + blk_next->size;
-                blk->flags.has_next = blk_next->flags.has_next;
-            }
-        }
-
-        // @param start_pos position where to start finding
-        // @param size the size of the block we're looking for
-        // @return found block if suitable block exists, if not, the last block
-        constexpr mem_blk* find_blk(mem_blk* start_pos, size_type size)
-        {
-            while (true) {
-                if (start_pos->flags.is_free) {
-                    unite_afterwards(start_pos);
-
-                    if (start_pos->size >= size)
-                        break;
-                }
-
-                if (!start_pos->flags.has_next)
-                    break;
-                start_pos = _next(start_pos, start_pos->size);
-            }
-            return start_pos;
-        }
-
-        constexpr mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
-        {
-            auto ret = sbrk(sizeof(mem_blk) + size);
-            if (!ret)
-                return nullptr;
-
-            mem_blk* blk = _next(blk_before, blk_before->size);
-
-            blk_before->flags.has_next = 1;
-
-            blk->flags.has_next = 0;
-            blk->flags.is_free = 1;
-            blk->size = size;
-
-            return blk;
-        }
-
-        constexpr void split_block(mem_blk* blk, size_type this_size)
-        {
-            // block is too small to get split
-            // that is, the block to be split should have enough room
-            // for "this_size" bytes and also could contain a new block
-            if (blk->size < this_size + sizeof(mem_blk) + 8)
-                return;
-
-            mem_blk* blk_next = _next(blk, this_size);
-
-            blk_next->size = blk->size
-                - this_size
-                - sizeof(mem_blk);
-
-            blk_next->flags.has_next = blk->flags.has_next;
-            blk_next->flags.is_free = 1;
-
-            blk->flags.has_next = 1;
-            blk->size = this_size;
-        }
-
-    public:
-        constexpr brk_memory_allocator(byte* start, size_type limit)
-            : p_start(start)
-            , p_limit(start + limit)
-        {
-            brk(p_start);
-            auto* p_blk = std::bit_cast<mem_blk*>(sbrk(0));
-            p_blk->size = 8;
-            p_blk->flags.has_next = 0;
-            p_blk->flags.is_free = 1;
-        }
+#include <kernel/async/lock.hpp>
 
-        constexpr void* alloc(size_type size)
-        {
-            // align to 8 bytes boundary
-            size = (size + 7) & ~7;
+namespace types::memory {
 
-            auto* block_allocated = find_blk(std::bit_cast<mem_blk*>(p_start), size);
-            if (!block_allocated->flags.has_next
-                && (!block_allocated->flags.is_free || block_allocated->size < size)) {
-                // 'block_allocated' in the argument list is the pointer
-                // pointing to the last block
-                block_allocated = allocate_new_block(block_allocated, size);
-                if (!block_allocated)
-                    return nullptr;
-            } else {
-                split_block(block_allocated, size);
-            }
+class brk_memory_allocator {
+   public:
+    using byte = std::byte;
+    using size_type = std::size_t;
 
-            block_allocated->flags.is_free = 0;
+   private:
+    byte* p_start;
+    byte* p_limit;
+    byte* p_break;
+    byte* p_allocated;
+    kernel::async::mutex mtx;
 
-            auto* blkpos = std::bit_cast<byte*>(block_allocated);
-            if (blkpos > p_start)
-                p_start = blkpos;
-            return block_allocated->data;
-        }
+    byte* brk(byte* addr);
+    byte* sbrk(size_type increment);
 
-        constexpr void free(void* ptr)
-        {
-            auto* blk = std::bit_cast<mem_blk*>(
-                std::bit_cast<byte*>(ptr) - sizeof(mem_blk));
+    constexpr byte* sbrk() const noexcept { return p_break; }
 
-            blk->flags.is_free = 1;
+   public:
+    explicit brk_memory_allocator(byte* start, size_type size);
+    brk_memory_allocator(const brk_memory_allocator&) = delete;
 
-            if (std::bit_cast<byte*>(blk) < p_start)
-                p_start = std::bit_cast<byte*>(blk);
+    void* allocate(size_type size);
+    void deallocate(void* ptr);
 
-            // unite free blocks nearby
-            unite_afterwards(blk);
-        }
-    };
-}; // namespace __allocator
-
-template <typename T>
-concept Allocator = requires(size_t size, typename T::value_type* ptr)
-{
-    typename T::value_type;
-    {
-        T::allocate_memory(size)
-    };
-    {
-        T::deallocate_memory(ptr)
-    };
-    std::is_same_v<typename T::value_type*, decltype(T::allocate_memory(size))>;
-    std::is_same_v<void, decltype(T::deallocate_memory(ptr))>;
-};
-
-template <Allocator T>
-class allocator_traits;
-
-namespace __allocator {
-    inline char __ident_heap[0x100000];
-    inline __allocator::brk_memory_allocator
-        m_alloc { (uint8_t*)__ident_heap, sizeof(__ident_heap) };
-} // namespace __allocator
-
-template <typename T>
-class kernel_ident_allocator {
-public:
-    using value_type = T;
-
-    static constexpr value_type* allocate_memory(size_t count)
-    {
-        return static_cast<value_type*>(__allocator::m_alloc.alloc(count));
-    }
-
-    static constexpr void deallocate_memory(value_type* ptr)
-    {
-        __allocator::m_alloc.free(ptr);
-    }
-};
-
-template <template <typename _T> class Allocator, typename T, typename... Args>
-constexpr T* _new(Args&&... args)
-{
-    return allocator_traits<Allocator<T>>::allocate_and_construct(std::forward<Args>(args)...);
-}
-
-template <template <typename _T> class Allocator, typename T, typename... Args>
-constexpr T* pnew(T* = nullptr, Args&&... args)
-{
-    return _new<Allocator, T, Args...>(std::forward<Args>(args)...);
-}
-
-template <template <typename _T> class Allocator, typename T>
-constexpr void pdelete(T* ptr)
-{
-    allocator_traits<Allocator<T>>::deconstruct_and_deallocate(ptr);
-}
-
-template <Allocator _allocator>
-class allocator_traits {
-public:
-    using value_type = typename _allocator::value_type;
-
-    static constexpr value_type* allocate(size_t count)
-    {
-        if (count == 0)
-            return nullptr;
-        return _allocator::allocate_memory(sizeof(value_type) * count);
-    }
-
-    template <typename... Args>
-    static constexpr value_type* construct(value_type* ptr, Args&&... args)
-    {
-        new (ptr) value_type(std::forward<Args>(args)...);
-        return ptr;
-    }
-
-    template <typename... Args>
-    static constexpr value_type* allocate_and_construct(Args&&... args)
-    {
-        auto* ptr = allocate(1);
-        construct(ptr, std::forward<Args>(args)...);
-        return ptr;
-    }
-
-    static constexpr void deconstruct(value_type* ptr)
-    {
-        if (!ptr)
-            return;
-        ptr->~value_type();
-    }
-
-    static constexpr void deallocate(value_type* ptr)
-    {
-        if (!ptr)
-            return;
-        _allocator::deallocate_memory(ptr);
-    }
-
-    static constexpr void deconstruct_and_deallocate(value_type* ptr)
-    {
-        if (!ptr)
-            return;
-        deconstruct(ptr);
-        deallocate(ptr);
-    }
+    bool allocated(void* ptr) const noexcept;
 };
 
-namespace __allocator {
-    inline __allocator::brk_memory_allocator* m_palloc;
-    inline void init_kernel_heap(void* start, size_t sz)
-    {
-        m_palloc = pnew<kernel_ident_allocator>(m_palloc, (uint8_t*)start, sz);
-    }
-} // namespace __allocator
-
-template <typename T>
-class kernel_allocator {
-public:
-    using value_type = T;
-
-    static constexpr value_type* allocate_memory(size_t count)
-    {
-        return static_cast<value_type*>(__allocator::m_palloc->alloc(count));
-    }
+} // namespace types::memory
 
-    static constexpr void deallocate_memory(value_type* ptr)
-    {
-        __allocator::m_palloc->free(ptr);
-    }
-};
-
-template <typename T, template <typename> typename Allocator>
-struct allocator_adapter {
-    using value_type = typename Allocator<T>::value_type;
-    using propagate_on_container_move_assignment = std::true_type;
-
-    constexpr allocator_adapter() = default;
-
-    template <template <typename> typename UAlloc, typename U>
-    constexpr allocator_adapter(const allocator_adapter<U, UAlloc>&)
-        noexcept {}
-    
-    constexpr T* allocate(std::size_t n)
-    { return types::allocator_traits<Allocator<T>>::allocate(n); }
-    constexpr void deallocate(T* ptr, std::size_t)
-    { return types::allocator_traits<Allocator<T>>::deallocate(ptr); }
-
-    template <typename U>
-    struct rebind { using other = allocator_adapter<U, Allocator>; };
-};
+namespace kernel::kinit {
+void init_allocator();
 
-} // namespace types
+} // namespace kernel::kinit

+ 21 - 27
include/types/bitmap.hpp

@@ -6,47 +6,41 @@
 namespace types {
 
 class bitmap {
-public:
+   public:
     using deleter_type = std::function<void(unsigned char*, std::size_t)>;
 
-private:
+   private:
     deleter_type m_del;
-    unsigned char* m_bm;
     std::size_t m_size;
+    unsigned char* m_bm;
 
-    static constexpr std::size_t SZ = sizeof(unsigned char);
+    static constexpr std::size_t SZ = sizeof(unsigned char) * 8;
 
-public:
-    constexpr bitmap(const deleter_type& del, unsigned char* bm, std::size_t size)
-        : m_del(del), m_bm(bm), m_size(size) {}
+   public:
+    constexpr bitmap(const deleter_type& del, unsigned char* bm,
+                     std::size_t size)
+        : m_del(del), m_size(size), m_bm(bm) {}
     constexpr bitmap(deleter_type&& del, unsigned char* bm, std::size_t size)
-        : m_del(std::move(del)), m_bm(bm), m_size(size) {}
+        : m_del(std::move(del)), m_size(size), m_bm(bm) {}
 
     explicit constexpr bitmap(std::size_t size)
-    {
-        m_size = (size / SZ) + ((size % SZ) ? 1 : 0);
-        m_bm = new unsigned char[m_size] {};
-        m_del = [](unsigned char* bm, std::size_t) {
-            delete[] bm;
-        };
-    }
+        : m_del{[](unsigned char* bm, std::size_t) { delete[] bm; }}
+        , m_size{(size / SZ) + ((size % SZ) ? 1 : 0)}
+        , m_bm{new unsigned char[m_size]{}} {}
 
     bitmap(const bitmap&) = delete;
-    
-    constexpr ~bitmap()
-    { m_del(m_bm, m_size); }
-    
-    constexpr bool test(std::size_t n) const
-    { return (m_bm[n / SZ] & (1 << (n % SZ))) != 0; }
 
-    constexpr void set(std::size_t n)
-    { m_bm[n / SZ] |= (1 << (n % SZ)); }
+    constexpr ~bitmap() { m_del(m_bm, m_size); }
+
+    constexpr bool test(std::size_t n) const {
+        return (m_bm[n / SZ] & (1 << (n % SZ))) != 0;
+    }
+
+    constexpr void set(std::size_t n) { m_bm[n / SZ] |= (1 << (n % SZ)); }
 
-    constexpr void clear(std::size_t n)
-    { m_bm[n / SZ] &= (~(1 << (n % SZ))); }
+    constexpr void clear(std::size_t n) { m_bm[n / SZ] &= (~(1 << (n % SZ))); }
 
-    constexpr std::size_t size() const noexcept
-    { return m_size; }
+    constexpr std::size_t size() const noexcept { return m_size; }
 };
 
 } // namespace types

+ 50 - 71
include/types/buffer.hpp

@@ -1,112 +1,98 @@
 #pragma once
 
+#include <memory>
+
 #include <stdint.h>
 #include <stdio.h>
+
 #include <types/allocator.hpp>
 
 namespace types {
 
-template <template <typename> class Allocator>
-class buffer {
-public:
-    using allocator_type = Allocator<char>;
+template <typename Allocator>
+class basic_buffer {
+   public:
+    using alloc_traits = std::allocator_traits<Allocator>;
 
-private:
+   private:
     char* const start;
     char* const end;
     char* base;
     char* head;
     size_t count;
+    Allocator alloc{};
 
-private:
-    constexpr char _get_char(char* ptr)
-    {
+   private:
+    constexpr char _get_char(char* ptr) {
         --count;
         return *ptr;
     }
 
-    constexpr void _put_char(char c)
-    {
+    constexpr void _put_char(char c) {
         *head = c;
         ++count;
     }
 
-    constexpr char* _forward(char* ptr)
-    {
+    constexpr char* _forward(char* ptr) {
         if (ptr == end)
             return start;
         else
             return ptr + 1;
     }
 
-    constexpr char* _backward(char* ptr)
-    {
+    constexpr char* _backward(char* ptr) {
         if (ptr == start)
             return end;
         else
             return ptr - 1;
     }
 
-public:
-    constexpr buffer(size_t size)
-        : start { types::allocator_traits<allocator_type>::allocate(size) }
-        , end { start + size - 1 }
-        , base { start }
-        , head { start }
-        , count { 0 }
-    {
-    }
-
-    constexpr buffer(const buffer& buf)
-        : start { types::allocator_traits<allocator_type>::allocate(buf.end + 1 - buf.start) }
-        , end { (uint32_t)start + (uint32_t)buf.end - (uint32_t)buf.start }
-        , base { (uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start }
-        , head { (uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start }
-        , count { buf.count }
-    {
-    }
-
-    constexpr buffer(buffer&& buf)
-        : start { buf.start }
-        , end { buf.end }
-        , base { buf.base }
-        , head { buf.head }
-        , count { buf.count }
-    {
-    }
-
-    constexpr ~buffer()
-    {
+   public:
+    constexpr basic_buffer(size_t size)
+        : start{alloc_traits::allocate(alloc, size)}
+        , end{start + size - 1}
+        , base{start}
+        , head{start}
+        , count{0} {}
+
+    constexpr basic_buffer(const basic_buffer& buf)
+        : start{alloc_traits::allocate(alloc, buf.end + 1 - buf.start)}
+        , end{(uint32_t)start + (uint32_t)buf.end - (uint32_t)buf.start}
+        , base{(uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start}
+        , head{(uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start}
+        , count{buf.count} {}
+
+    constexpr basic_buffer(basic_buffer&& buf)
+        : start{buf.start}
+        , end{buf.end}
+        , base{buf.base}
+        , head{buf.head}
+        , count{buf.count} {}
+
+    constexpr ~basic_buffer() {
         if (start)
-            types::allocator_traits<allocator_type>::deallocate(start);
+            alloc_traits::deallocate(alloc, start, end - start);
     }
 
-    constexpr bool empty(void) const
-    {
-        return count == 0;
-    }
+    constexpr bool empty(void) const { return count == 0; }
 
-    constexpr bool full(void) const
-    {
+    constexpr bool full(void) const {
         return count == static_cast<size_t>(end - start + 1);
     }
 
-    constexpr int front(void)
-    {
+    constexpr int front(void) {
         if (empty())
             return EOF;
         return *base;
     }
 
-    constexpr int back(void)
-    {
+    constexpr int back(void) {
         if (empty())
             return EOF;
         return *_backward(head);
     }
 
-    constexpr int get(void)
-    {
+    constexpr int get(void) {
         if (empty())
             return EOF;
 
@@ -115,8 +101,7 @@ public:
         return c;
     }
 
-    constexpr int pop(void)
-    {
+    constexpr int pop(void) {
         if (empty())
             return EOF;
 
@@ -125,8 +110,7 @@ public:
         return c;
     }
 
-    constexpr int put(char c)
-    {
+    constexpr int put(char c) {
         if (full())
             return EOF;
 
@@ -135,21 +119,16 @@ public:
         return c;
     }
 
-    constexpr size_t size(void) const
-    {
-        return count;
-    }
+    constexpr size_t size(void) const { return count; }
 
-    constexpr size_t avail(void) const
-    {
-        return end - start + 1 - count;
-    }
+    constexpr size_t avail(void) const { return end - start + 1 - count; }
 
-    constexpr void clear(void)
-    {
+    constexpr void clear(void) {
         count = 0;
         head = base;
     }
 };
 
+using buffer = basic_buffer<std::allocator<char>>;
+
 } // namespace types

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio