aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2025-12-15 17:13:12 +0100
committerFelix Morgner <felix.morgner@ost.ch>2025-12-15 17:13:12 +0100
commit7b9482ae637126ac9337876e60f519b493437711 (patch)
tree6fc71a253c8b0325d303bd34c95b564ba536ed14
parent116f9332a206767c45095950f09f7c7447b561cf (diff)
parenta9eeec745e29d89afd48ee43d09432eb6fc35be7 (diff)
downloadkernel-7b9482ae637126ac9337876e60f519b493437711.tar.xz
kernel-7b9482ae637126ac9337876e60f519b493437711.zip
os: rework kernel architecture
Rework the code structure and architecture of the kernel by separating platform-dependent and platform-independent code more cleanly. As of this patchset, full feature parity has not been achieved. Nonetheless, a sufficient subset of functionality has been ported to the new architecture to demonstrate the feasibility of the new structure.
-rw-r--r--.clang-format163
-rw-r--r--.clang-tidy7
-rw-r--r--.clangd3
-rw-r--r--.devcontainer/x86-64/devcontainer.json37
-rw-r--r--.gitignore14
-rw-r--r--.vscode/extensions.json6
-rw-r--r--.vscode/launch.json31
-rw-r--r--.vscode/settings.json42
-rw-r--r--.vscode/tasks.json6
-rw-r--r--CMakeLists.txt151
-rw-r--r--CMakePresets.json25
-rw-r--r--Doxyfile2974
-rw-r--r--arch/x86_64/CMakeLists.txt176
-rw-r--r--arch/x86_64/include/arch/boot/pointers.hpp15
-rw-r--r--arch/x86_64/include/arch/io/port_io.hpp133
-rw-r--r--arch/x86_64/include/arch/kernel/cpu/control_register.hpp71
-rw-r--r--arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp67
-rw-r--r--arch/x86_64/include/arch/memory/allocator/concept.hpp21
-rw-r--r--arch/x86_64/include/arch/memory/allocator/physical_frame.hpp86
-rw-r--r--arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp74
-rw-r--r--arch/x86_64/include/arch/memory/main.hpp30
-rw-r--r--arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp169
-rw-r--r--arch/x86_64/include/arch/memory/multiboot/memory_map.hpp53
-rw-r--r--arch/x86_64/include/arch/memory/multiboot/reader.hpp53
-rw-r--r--arch/x86_64/include/arch/memory/paging/active_page_table.hpp206
-rw-r--r--arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp39
-rw-r--r--arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp180
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_entry.hpp121
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_table.hpp157
-rw-r--r--arch/x86_64/include/arch/memory/paging/temporary_page.hpp64
-rw-r--r--arch/x86_64/include/arch/memory/paging/virtual_page.hpp91
-rw-r--r--arch/x86_64/include/arch/stl/container.hpp99
-rw-r--r--arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp216
-rw-r--r--arch/x86_64/include/arch/stl/forward_value_iterator.hpp121
-rw-r--r--arch/x86_64/include/arch/video/vga/io.hpp39
-rw-r--r--arch/x86_64/include/arch/video/vga/text.hpp169
-rw-r--r--arch/x86_64/include/x86_64/boot/boot.hpp70
-rw-r--r--arch/x86_64/include/x86_64/boot/ld.hpp61
-rw-r--r--arch/x86_64/include/x86_64/cpu/control_register.hpp244
-rw-r--r--arch/x86_64/include/x86_64/cpu/model_specific_register.hpp148
-rw-r--r--arch/x86_64/include/x86_64/cpu/registers.hpp30
-rw-r--r--arch/x86_64/include/x86_64/device_io/port_io.hpp101
-rw-r--r--arch/x86_64/include/x86_64/memory/buffered_allocator.hpp68
-rw-r--r--arch/x86_64/include/x86_64/memory/kernel_mapper.hpp32
-rw-r--r--arch/x86_64/include/x86_64/memory/mmu.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/tlb.hpp)14
-rw-r--r--arch/x86_64/include/x86_64/memory/page_table.hpp341
-rw-r--r--arch/x86_64/include/x86_64/memory/page_utilities.hpp22
-rw-r--r--arch/x86_64/include/x86_64/memory/paging_root.hpp27
-rw-r--r--arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp23
-rw-r--r--arch/x86_64/include/x86_64/memory/region_allocator.hpp79
-rw-r--r--arch/x86_64/include/x86_64/memory/scoped_mapping.hpp66
-rw-r--r--arch/x86_64/include/x86_64/vga/crtc.hpp39
-rw-r--r--arch/x86_64/include/x86_64/vga/text.hpp178
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp (renamed from arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp (renamed from arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp (renamed from arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp (renamed from arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp (renamed from arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp (renamed from arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp)6
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/main.hpp (renamed from arch/x86_64/include/arch/context_switching/main.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/access_byte.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp (renamed from arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp (renamed from arch/x86_64/include/arch/context_switching/syscall/main.hpp)5
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp (renamed from arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp (renamed from arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/exception_handling/assert.hpp (renamed from arch/x86_64/include/arch/exception_handling/assert.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/exception_handling/panic.hpp (renamed from arch/x86_64/include/arch/exception_handling/panic.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp (renamed from arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/call.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/call.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/gdtr.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/idtr.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/if.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/if.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/msr.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/segment_register.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/tr.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/halt.hpp (renamed from arch/x86_64/include/arch/kernel/halt.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/kernel/main.hpp (renamed from arch/x86_64/include/arch/kernel/main.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/memory/heap/bump_allocator.hpp (renamed from arch/x86_64/include/arch/memory/heap/bump_allocator.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp (renamed from arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp)19
-rw-r--r--arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp (renamed from arch/x86_64/include/arch/memory/heap/heap_allocator.hpp)8
-rw-r--r--arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp (renamed from arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp)10
-rw-r--r--arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp (renamed from arch/x86_64/include/arch/memory/heap/memory_block.hpp)0
-rw-r--r--arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp (renamed from arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp)11
-rw-r--r--arch/x86_64/pre/include/arch/user/main.hpp (renamed from arch/x86_64/include/arch/user/main.hpp)0
-rw-r--r--arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp (renamed from arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp)0
-rw-r--r--arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp (renamed from arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp)5
-rw-r--r--arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp (renamed from arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp)2
-rw-r--r--arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp (renamed from arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp)0
-rw-r--r--arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp (renamed from arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp)0
-rw-r--r--arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp (renamed from arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp)15
-rw-r--r--arch/x86_64/pre/src/context_switching/main.cpp (renamed from arch/x86_64/src/context_switching/main.cpp)13
-rw-r--r--arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp (renamed from arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp)5
-rw-r--r--arch/x86_64/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp (renamed from arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp)10
-rw-r--r--arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp (renamed from arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp)10
-rw-r--r--arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp (renamed from arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp)0
-rw-r--r--arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp (renamed from arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp)5
-rw-r--r--arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp (renamed from arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp)10
-rw-r--r--arch/x86_64/pre/src/context_switching/syscall/main.cpp (renamed from arch/x86_64/src/context_switching/syscall/main.cpp)2
-rw-r--r--arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp (renamed from arch/x86_64/src/context_switching/syscall/syscall_enable.cpp)10
-rw-r--r--arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp (renamed from arch/x86_64/src/context_switching/syscall/syscall_handler.cpp)11
-rw-r--r--arch/x86_64/pre/src/exception_handling/abort.cpp (renamed from arch/x86_64/src/exception_handling/abort.cpp)5
-rw-r--r--arch/x86_64/pre/src/exception_handling/assert.cpp (renamed from arch/x86_64/src/exception_handling/assert.cpp)0
-rw-r--r--arch/x86_64/pre/src/exception_handling/panic.cpp (renamed from arch/x86_64/src/exception_handling/panic.cpp)5
-rw-r--r--arch/x86_64/pre/src/exception_handling/pure_virtual.cpp (renamed from arch/x86_64/src/exception_handling/pure_virtual.cpp)0
-rw-r--r--arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp (renamed from arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp)0
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/call.cpp (renamed from arch/x86_64/src/kernel/cpu/call.cpp)0
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/gdtr.cpp (renamed from arch/x86_64/src/kernel/cpu/gdtr.cpp)0
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/idtr.cpp (renamed from arch/x86_64/src/kernel/cpu/idtr.cpp)0
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/if.cpp13
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/msr.cpp (renamed from arch/x86_64/src/kernel/cpu/msr.cpp)2
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/segment_register.cpp (renamed from arch/x86_64/src/kernel/cpu/segment_register.cpp)0
-rw-r--r--arch/x86_64/pre/src/kernel/cpu/tr.cpp (renamed from arch/x86_64/src/kernel/cpu/tr.cpp)0
-rw-r--r--arch/x86_64/pre/src/kernel/main.cpp (renamed from arch/x86_64/src/kernel/main.cpp)0
-rw-r--r--arch/x86_64/pre/src/memory/heap/bump_allocator.cpp (renamed from arch/x86_64/src/memory/heap/bump_allocator.cpp)0
-rw-r--r--arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp (renamed from arch/x86_64/src/memory/heap/global_heap_allocator.cpp)33
-rw-r--r--arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp (renamed from arch/x86_64/src/memory/heap/linked_list_allocator.cpp)2
-rw-r--r--arch/x86_64/pre/src/memory/heap/memory_block.cpp (renamed from arch/x86_64/src/memory/heap/memory_block.cpp)5
-rw-r--r--arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp (renamed from arch/x86_64/src/memory/heap/user_heap_allocator.cpp)4
-rw-r--r--arch/x86_64/pre/src/user/main.cpp (renamed from arch/x86_64/src/user/main.cpp)0
-rw-r--r--arch/x86_64/scripts/kernel.ld73
-rw-r--r--arch/x86_64/src/boot/boot.s368
-rw-r--r--arch/x86_64/src/boot/boot32.S449
-rw-r--r--arch/x86_64/src/boot/crti.s13
-rw-r--r--arch/x86_64/src/boot/crtn.s9
-rw-r--r--arch/x86_64/src/boot/entry64.s60
-rw-r--r--arch/x86_64/src/boot/initialize_runtime.cpp26
-rw-r--r--arch/x86_64/src/kapi/cio.cpp20
-rw-r--r--arch/x86_64/src/kapi/cpu.cpp12
-rw-r--r--arch/x86_64/src/kapi/memory.cpp193
-rw-r--r--arch/x86_64/src/kernel/cpu/control_register.cpp66
-rw-r--r--arch/x86_64/src/kernel/cpu/if.cpp7
-rw-r--r--arch/x86_64/src/kernel/cpu/tlb.cpp16
-rw-r--r--arch/x86_64/src/memory/allocator/area_frame_allocator.cpp85
-rw-r--r--arch/x86_64/src/memory/allocator/physical_frame.cpp24
-rw-r--r--arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp34
-rw-r--r--arch/x86_64/src/memory/kernel_mapper.cpp111
-rw-r--r--arch/x86_64/src/memory/main.cpp77
-rw-r--r--arch/x86_64/src/memory/mmu.cpp21
-rw-r--r--arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp13
-rw-r--r--arch/x86_64/src/memory/multiboot/reader.cpp131
-rw-r--r--arch/x86_64/src/memory/page_table.cpp82
-rw-r--r--arch/x86_64/src/memory/paging/active_page_table.cpp98
-rw-r--r--arch/x86_64/src/memory/paging/inactive_page_table.cpp20
-rw-r--r--arch/x86_64/src/memory/paging/page_entry.cpp63
-rw-r--r--arch/x86_64/src/memory/paging/page_table.cpp128
-rw-r--r--arch/x86_64/src/memory/paging/temporary_page.cpp29
-rw-r--r--arch/x86_64/src/memory/paging/virtual_page.cpp33
-rw-r--r--arch/x86_64/src/memory/paging_root.cpp19
-rw-r--r--arch/x86_64/src/memory/recursive_page_mapper.cpp119
-rw-r--r--arch/x86_64/src/memory/region_allocator.cpp92
-rw-r--r--arch/x86_64/src/memory/scoped_mapping.cpp69
-rw-r--r--arch/x86_64/src/stl/mutex.cpp16
-rw-r--r--arch/x86_64/src/vga/text.cpp84
-rw-r--r--arch/x86_64/src/video/vga/text.cpp66
-rw-r--r--arch/x86_64/support/grub.cfg.in2
-rw-r--r--arch/x86_64/x86_64.dox14
-rw-r--r--cmake/Modules/ElfTransformations.cmake36
-rw-r--r--cmake/Modules/GenerateBootableIso.cmake22
-rw-r--r--cmake/Platforms/x86_64.cmake62
-rw-r--r--docs/arch.rst9
-rw-r--r--docs/briefs.rst9
-rw-r--r--docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst161
-rw-r--r--docs/briefs/tb0002-x86_64_bootstrap.rst154
-rw-r--r--docs/conf.py8
-rw-r--r--docs/cross.rst9
-rw-r--r--docs/index.rst3
-rw-r--r--docs/pre/arch/x86_64.rst (renamed from docs/arch/x86_64.rst)0
-rw-r--r--docs/pre/arch/x86_64/boot.rst (renamed from docs/arch/x86_64/boot.rst)0
-rw-r--r--docs/pre/arch/x86_64/boot/pointers.rst (renamed from docs/arch/x86_64/boot/pointers.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching.rst (renamed from docs/arch/x86_64/context_switching.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst (renamed from docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/main.rst (renamed from docs/arch/x86_64/context_switching/main.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst (renamed from docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/syscall.rst (renamed from docs/arch/x86_64/context_switching/syscall.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/syscall/main.rst (renamed from docs/arch/x86_64/context_switching/syscall/main.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst (renamed from docs/arch/x86_64/context_switching/syscall/syscall_enable.rst)0
-rw-r--r--docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst (renamed from docs/arch/x86_64/context_switching/syscall/syscall_handler.rst)0
-rw-r--r--docs/pre/arch/x86_64/exception_handling.rst (renamed from docs/arch/x86_64/exception_handling.rst)0
-rw-r--r--docs/pre/arch/x86_64/exception_handling/assert.rst (renamed from docs/arch/x86_64/exception_handling/assert.rst)0
-rw-r--r--docs/pre/arch/x86_64/exception_handling/panic.rst (renamed from docs/arch/x86_64/exception_handling/panic.rst)0
-rw-r--r--docs/pre/arch/x86_64/interrupt_handling.rst (renamed from docs/arch/x86_64/interrupt_handling.rst)0
-rw-r--r--docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst (renamed from docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst)0
-rw-r--r--docs/pre/arch/x86_64/io.rst (renamed from docs/arch/x86_64/io.rst)0
-rw-r--r--docs/pre/arch/x86_64/io/port_io.rst (renamed from docs/arch/x86_64/io/port_io.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel.rst (renamed from docs/arch/x86_64/kernel.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu.rst (renamed from docs/arch/x86_64/kernel/cpu.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/call.rst (renamed from docs/arch/x86_64/kernel/cpu/call.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/control_register.rst (renamed from docs/arch/x86_64/kernel/cpu/control_register.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/gdtr.rst (renamed from docs/arch/x86_64/kernel/cpu/gdtr.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/idtr.rst (renamed from docs/arch/x86_64/kernel/cpu/idtr.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/if.rst (renamed from docs/arch/x86_64/kernel/cpu/if.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/msr.rst (renamed from docs/arch/x86_64/kernel/cpu/msr.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/segment_register.rst (renamed from docs/arch/x86_64/kernel/cpu/segment_register.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/tlb.rst (renamed from docs/arch/x86_64/kernel/cpu/tlb.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/cpu/tr.rst (renamed from docs/arch/x86_64/kernel/cpu/tr.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/halt.rst (renamed from docs/arch/x86_64/kernel/halt.rst)0
-rw-r--r--docs/pre/arch/x86_64/kernel/main.rst (renamed from docs/arch/x86_64/kernel/main.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory.rst (renamed from docs/arch/x86_64/memory.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/allocator.rst (renamed from docs/arch/x86_64/memory/allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst (renamed from docs/arch/x86_64/memory/allocator/area_frame_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/allocator/concept.rst (renamed from docs/arch/x86_64/memory/allocator/concept.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/allocator/physical_frame.rst (renamed from docs/arch/x86_64/memory/allocator/physical_frame.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst (renamed from docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/cpu.rst (renamed from docs/arch/x86_64/memory/cpu.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap.rst (renamed from docs/arch/x86_64/memory/heap.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap/bump_allocator.rst (renamed from docs/arch/x86_64/memory/heap/bump_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst (renamed from docs/arch/x86_64/memory/heap/global_heap_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap/heap_allocator.rst (renamed from docs/arch/x86_64/memory/heap/heap_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst (renamed from docs/arch/x86_64/memory/heap/linked_list_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap/memory_block.rst (renamed from docs/arch/x86_64/memory/heap/memory_block.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst (renamed from docs/arch/x86_64/memory/heap/user_heap_allocator.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/main.rst (renamed from docs/arch/x86_64/memory/main.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/multiboot.rst (renamed from docs/arch/x86_64/memory/multiboot.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst (renamed from docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/multiboot/info.rst (renamed from docs/arch/x86_64/memory/multiboot/info.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/multiboot/memory_map.rst (renamed from docs/arch/x86_64/memory/multiboot/memory_map.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/multiboot/reader.rst (renamed from docs/arch/x86_64/memory/multiboot/reader.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging.rst (renamed from docs/arch/x86_64/memory/paging.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/active_page_table.rst (renamed from docs/arch/x86_64/memory/paging/active_page_table.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst (renamed from docs/arch/x86_64/memory/paging/inactive_page_table.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst (renamed from docs/arch/x86_64/memory/paging/kernel_mapper.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/page_entry.rst (renamed from docs/arch/x86_64/memory/paging/page_entry.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/page_table.rst (renamed from docs/arch/x86_64/memory/paging/page_table.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/temporary_page.rst (renamed from docs/arch/x86_64/memory/paging/temporary_page.rst)0
-rw-r--r--docs/pre/arch/x86_64/memory/paging/virtual_page.rst (renamed from docs/arch/x86_64/memory/paging/virtual_page.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl.rst (renamed from docs/arch/x86_64/stl.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/container.rst (renamed from docs/arch/x86_64/stl/container.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst (renamed from docs/arch/x86_64/stl/contiguous_pointer_iterator.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/forward_value_iterator.rst (renamed from docs/arch/x86_64/stl/forward_value_iterator.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/mutex.rst (renamed from docs/arch/x86_64/stl/mutex.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/shared_pointer.rst (renamed from docs/arch/x86_64/stl/shared_pointer.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/stack.rst (renamed from docs/arch/x86_64/stl/stack.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/unique_pointer.rst (renamed from docs/arch/x86_64/stl/unique_pointer.rst)0
-rw-r--r--docs/pre/arch/x86_64/stl/vector.rst (renamed from docs/arch/x86_64/stl/vector.rst)0
-rw-r--r--docs/pre/arch/x86_64/user.rst (renamed from docs/arch/x86_64/user.rst)0
-rw-r--r--docs/pre/arch/x86_64/user/main.rst (renamed from docs/arch/x86_64/user/main.rst)0
-rw-r--r--docs/pre/arch/x86_64/video.rst (renamed from docs/arch/x86_64/video.rst)0
-rw-r--r--docs/pre/arch/x86_64/video/vga.rst (renamed from docs/arch/x86_64/video/vga.rst)0
-rw-r--r--docs/pre/arch/x86_64/video/vga/io.rst (renamed from docs/arch/x86_64/video/vga/io.rst)0
-rw-r--r--docs/pre/arch/x86_64/video/vga/text.rst (renamed from docs/arch/x86_64/video/vga/text.rst)0
-rw-r--r--docs/pre/cross/memory.rst (renamed from docs/cross/memory.rst)0
-rw-r--r--docs/pre/cross/memory/asm_pointer.rst (renamed from docs/cross/memory/asm_pointer.rst)0
-rw-r--r--docs/requirements.txt2
-rw-r--r--include/memory/asm_pointer.hpp76
-rw-r--r--kapi/CMakeLists.txt34
-rw-r--r--kapi/include/kapi/boot.hpp17
-rw-r--r--kapi/include/kapi/cio.hpp51
-rw-r--r--kapi/include/kapi/cio/output_device.hpp47
-rw-r--r--kapi/include/kapi/cpu.hpp13
-rw-r--r--kapi/include/kapi/memory.hpp70
-rw-r--r--kapi/include/kapi/memory/address.hpp101
-rw-r--r--kapi/include/kapi/memory/chunk.hpp104
-rw-r--r--kapi/include/kapi/memory/frame.hpp39
-rw-r--r--kapi/include/kapi/memory/frame_allocator.hpp43
-rw-r--r--kapi/include/kapi/memory/page.hpp39
-rw-r--r--kapi/include/kapi/memory/page_mapper.hpp87
-rw-r--r--kapi/include/kapi/system.hpp20
-rw-r--r--kernel/CMakeLists.txt36
-rw-r--r--kernel/src/kapi/cio.cpp57
-rw-r--r--kernel/src/kapi/memory.cpp91
-rw-r--r--kernel/src/kapi/system.cpp23
-rw-r--r--kernel/src/kstd.cpp16
-rw-r--r--kernel/src/main.cpp14
-rw-r--r--libs/CMakeLists.txt3
-rw-r--r--libs/elf/CMakeLists.txt19
-rw-r--r--libs/elf/include/elf/format.hpp15
-rw-r--r--libs/elf/include/elf/section_header.hpp99
-rw-r--r--libs/kstd/CMakeLists.txt40
-rw-r--r--libs/kstd/include/kstd/asm_ptr77
-rw-r--r--libs/kstd/include/kstd/bits/os.hpp34
-rw-r--r--libs/kstd/include/kstd/bits/shared_ptr.hpp (renamed from arch/x86_64/include/arch/stl/shared_pointer.hpp)56
-rw-r--r--libs/kstd/include/kstd/bits/unique_ptr.hpp (renamed from arch/x86_64/include/arch/stl/unique_pointer.hpp)42
-rw-r--r--libs/kstd/include/kstd/ext/bitfield_enum65
-rw-r--r--libs/kstd/include/kstd/memory7
-rw-r--r--libs/kstd/include/kstd/mutex (renamed from arch/x86_64/include/arch/stl/mutex.hpp)27
-rw-r--r--libs/kstd/include/kstd/stack (renamed from arch/x86_64/include/arch/stl/stack.hpp)45
-rw-r--r--libs/kstd/include/kstd/vector (renamed from arch/x86_64/include/arch/stl/vector.hpp)40
-rw-r--r--libs/kstd/kstd.dox14
-rw-r--r--libs/kstd/src/bits/os.cpp10
-rw-r--r--libs/kstd/src/libc/stdlib.cpp19
-rw-r--r--libs/kstd/src/libc/string.cpp32
-rw-r--r--libs/kstd/src/mutex.cpp24
-rw-r--r--libs/multiboot2/CMakeLists.txt27
-rw-r--r--libs/multiboot2/include/multiboot2/constants.hpp20
-rw-r--r--libs/multiboot2/include/multiboot2/impl/data.hpp135
-rw-r--r--libs/multiboot2/include/multiboot2/impl/ids.hpp (renamed from arch/x86_64/include/arch/memory/multiboot/info.hpp)67
-rw-r--r--libs/multiboot2/include/multiboot2/impl/iterator.hpp73
-rw-r--r--libs/multiboot2/include/multiboot2/impl/tag.hpp207
-rw-r--r--libs/multiboot2/include/multiboot2/information.hpp232
-rw-r--r--src/kernel/main.cpp9
310 files changed, 8980 insertions, 4331 deletions
diff --git a/.clang-format b/.clang-format
index d4da962..e54cb03 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,77 +1,120 @@
---
-AccessModifierOffset: '-2'
+AccessModifierOffset: "-2"
AlignAfterOpenBracket: Align
-AlignConsecutiveAssignments: 'false'
-AlignConsecutiveDeclarations: 'false'
-AlignEscapedNewlines: Left
-AlignOperands: 'true'
-AlignTrailingComments: 'true'
-AllowAllParametersOfDeclarationOnNextLine: 'true'
-AllowShortBlocksOnASingleLine: 'false'
-AllowShortCaseLabelsOnASingleLine: 'false'
-AllowShortFunctionsOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: 'false'
-AllowShortLoopsOnASingleLine: 'false'
+AlignConsecutiveAssignments:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: true
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: true
+AlignEscapedNewlines: LeftWithLastLine
+AlignTrailingComments: "true"
+AllowAllParametersOfDeclarationOnNextLine: "true"
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: "false"
+AllowShortFunctionsOnASingleLine: Empty
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: "false"
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
-AlwaysBreakTemplateDeclarations: 'true'
-BinPackArguments: 'true'
-BinPackParameters: 'true'
+AlwaysBreakTemplateDeclarations: "true"
+BinPackArguments: "true"
+BinPackParameters: "true"
BreakBeforeBraces: Custom
BraceWrapping:
- AfterClass: 'true'
- AfterControlStatement: 'true'
- AfterEnum: 'true'
- AfterFunction: 'true'
- AfterNamespace: 'true'
- AfterStruct: 'true'
- AfterUnion: 'true'
- AfterExternBlock: 'true'
- BeforeCatch: 'true'
- BeforeElse: 'true'
- IndentBraces: 'false'
-BreakBeforeInheritanceComma: 'false'
+ AfterClass: "true"
+ AfterControlStatement: "true"
+ AfterEnum: "true"
+ AfterFunction: "true"
+ AfterNamespace: "true"
+ AfterStruct: "true"
+ AfterUnion: "true"
+ AfterExternBlock: "true"
+ BeforeCatch: "true"
+ BeforeElse: "true"
+ IndentBraces: "false"
+ AfterCaseLabel: true
+ SplitEmptyFunction: false
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakBeforeInheritanceComma: "false"
BreakConstructorInitializers: BeforeComma
-BreakStringLiterals: 'true'
-ColumnLimit: '120'
-CompactNamespaces: 'false'
-Cpp11BracedListStyle: 'true'
-DerivePointerAlignment: 'false'
-FixNamespaceComments: 'true'
+BreakStringLiterals: "true"
+ColumnLimit: "120"
+CompactNamespaces: "false"
+Cpp11BracedListStyle: "true"
+DerivePointerAlignment: "false"
+FixNamespaceComments: "true"
IncludeBlocks: Regroup
IncludeCategories:
- # Local Headers
- - Regex: '"(.*/?)+/.+\.hpp"'
+ - Regex: 'kapi/[[:alnum:]._\/]+\.hpp'
Priority: 100
- # STL Headers
- - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>'
- Priority: 400
- # C Library Headers
- - Regex: '<([[:alnum:]._]/*)+\.h>'
+ - Regex: 'x86_64/[[:alnum:]._\/]+\.hpp'
+ Priority: 110
+ - Regex: '"[[:alnum:]._\/]+\.hpp"'
Priority: 300
-IndentCaseLabels: 'true'
+ - Regex: '<kstd/[[:alnum:]._\/]+>'
+ Priority: 400
+ - Regex: '<[[:alnum:]._\/]+\.hpp>'
+ Priority: 600
+ - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>'
+ Priority: 900
+IndentCaseLabels: "true"
IndentPPDirectives: None
-IndentWidth: '2'
-KeepEmptyLinesAtTheStartOfBlocks: 'false'
+IndentWidth: "2"
+KeepEmptyLinesAtTheStartOfBlocks: "false"
Language: Cpp
-MaxEmptyLinesToKeep: '1'
+MaxEmptyLinesToKeep: "1"
NamespaceIndentation: All
PointerAlignment: Middle
-ReflowComments: 'true'
-SortIncludes: 'true'
-SortUsingDeclarations: 'true'
-SpaceAfterCStyleCast: 'false'
-SpaceAfterTemplateKeyword: 'false'
-SpaceBeforeAssignmentOperators: 'true'
+ReflowComments: "true"
+SortIncludes: "true"
+SortUsingDeclarations: "true"
+SpaceAfterCStyleCast: "false"
+SpaceAfterTemplateKeyword: "false"
+SpaceBeforeAssignmentOperators: "true"
SpaceBeforeParens: ControlStatements
-SpaceInEmptyParentheses: 'false'
-SpacesBeforeTrailingComments: '2'
-SpacesInAngles: 'false'
-SpacesInContainerLiterals: 'false'
-SpacesInCStyleCastParentheses: 'false'
-SpacesInParentheses: 'false'
-SpacesInSquareBrackets: 'false'
-Standard: Cpp11
-TabWidth: '2'
+SpaceInEmptyParentheses: "false"
+SpacesBeforeTrailingComments: "2"
+SpacesInAngles: "false"
+SpacesInContainerLiterals: "false"
+SpacesInCStyleCastParentheses: "false"
+SpacesInParentheses: "false"
+SpacesInSquareBrackets: "false"
+Standard: Latest
+TabWidth: "2"
UseTab: Never
-...
+AlignArrayOfStructures: Right
+AlignConsecutiveBitFields: {}
+AllowAllArgumentsOnNextLine: false
+AllowBreakBeforeNoexceptSpecifier: Never
+AllowShortCaseExpressionOnASingleLine: false
+AllowShortCompoundRequirementOnASingleLine: true
+AllowShortEnumsOnASingleLine: false
+AllowShortLambdasOnASingleLine: Inline
+BitFieldColonSpacing: Both
+BracedInitializerIndentWidth: 2
+IntegerLiteralSeparator:
+ Binary: 4
+ BinaryMinDigits: 8
+ Decimal: 3
+ DecimalMinDigits: 6
+ Hex: 4
+ HexMinDigits: 8
+QualifierAlignment: Custom
+QualifierOrder:
+ - constexpr
+ - type
+ - static
+ - inline
+ - const
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..831bf8d
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,7 @@
+Checks:
+ - '-clang-diagnostic-*'
+ - 'clang-analyzer-*'
+ - 'cppcoreguidelines-*'
+ - '-cppcoreguidelines-owning-memory'
+ - 'modernize-*'
+ - 'misc-include-cleaner' \ No newline at end of file
diff --git a/.clangd b/.clangd
new file mode 100644
index 0000000..e3c98ed
--- /dev/null
+++ b/.clangd
@@ -0,0 +1,3 @@
+Diagnostics:
+ UnusedIncludes: Strict
+ MissingIncludes: Strict \ No newline at end of file
diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json
index a317a22..3599657 100644
--- a/.devcontainer/x86-64/devcontainer.json
+++ b/.devcontainer/x86-64/devcontainer.json
@@ -1,17 +1,24 @@
{
- "name": "TeachOS on x86-64",
- "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0",
- "customizations": {
- "vscode": {
- "extensions": [
- "basdp.language-gas-x86",
- "llvm-vs-code-extensions.vscode-clangd",
- "ms-vscode.cmake-tools",
- "webfreak.debug",
- "zixuanwang.linkerscript"
- ]
- }
- },
- "remoteUser": "dev",
- "updateRemoteUserUID": true
+ "name": "TeachOS on x86-64",
+ "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.2.0-2",
+ "features": {
+ "ghcr.io/devcontainers/features/git:1": {},
+ "ghcr.io/devcontainers/features/git-lfs:1": {},
+ "ghcr.io/devcontainers-extra/features/apt-packages:1": {
+ "packages": "cmake,grub2-common,grub-pc,mtools,ninja-build,qemu-system-x86,ssh,xorriso"
+ }
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "basdp.language-gas-x86",
+ "llvm-vs-code-extensions.vscode-clangd",
+ "ms-vscode.cmake-tools",
+ "KylinIdeTeam.cppdebug",
+ "zixuanwang.linkerscript"
+ ]
+ }
+ },
+ "remoteUser": "ubuntu",
+ "updateRemoteUserUID": true
}
diff --git a/.gitignore b/.gitignore
index d0c36aa..d575651 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,11 @@
-/.venv
+.venv/
+.cache/
+
+.gdb_history
+
+.devpod-internal/
+
/build
-/.conan/install
/docs/_build
-/.cache
-# Conan Generated CMake presets
-CMakeUserPresets.json
-.gdb_history
+qemu-*-*.log
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 69d954c..2b19ba3 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,5 +1,9 @@
{
"recommendations": [
- "ms-vscode-remote.vscode-remote-extensionpack"
+ "basdp.language-gas-x86",
+ "llvm-vs-code-extensions.vscode-clangd",
+ "ms-vscode.cmake-tools",
+ "KylinIdeTeam.cppdebug",
+ "zixuanwang.linkerscript"
]
} \ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index e522ad5..6478c96 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -3,18 +3,29 @@
"configurations": [
{
"name": "(gdb) QEMU",
- "type": "gdb",
- "request": "attach",
- "remote": true,
- "target": "localhost:1234",
- "valuesFormatting": "prettyPrinters",
- "gdbpath": "x86_64-pc-elf-gdb",
+ "type": "cppdbg",
+ "request": "launch",
"cwd": "${workspaceFolder}",
+ "stopAtEntry": true,
+ "miDebuggerServerAddress": "localhost:1234",
+ "miDebuggerPath": "x86_64-pc-elf-gdb",
"preLaunchTask": "QEMU (gdb)",
- "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/_kernel",
- "autorun": [
- "-enable-pretty-printing",
- "-break-insert _start"
+ "MIMode": "gdb",
+ "program": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.sym",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ },
+ {
+ "description": "Load code",
+ "text": "-file-exec-file ${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.elf"
+ },
+ {
+ "description": "Load symbols",
+ "text": "-file-exec-and-symbols ${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.sym"
+ }
]
}
]
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6178035..7f588f4 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,18 +1,44 @@
{
"cmake.useCMakePresets": "always",
"cmake.options.statusBarVisibility": "visible",
-
+
"clangd.arguments": [
"--compile-commands-dir=${workspaceFolder}/build",
- "--query-driver=/opt/toolchain/bin/x86_64-pc-elf-g++"
+ "--query-driver=**/x86_64-pc-elf-g++"
],
-
+
+ "files.associations": {
+ "**/kstd/include/kstd/**": "cpp",
+ },
+
"[cpp]": {
"editor.formatOnSave": true,
"editor.tabSize": 2,
},
-
- "[python]": {
- "editor.defaultFormatter": "ms-python.black-formatter"
- },
- } \ No newline at end of file
+
+ "[gas]": {
+ "editor.rulers": [
+ 80
+ ]
+ },
+ "cSpell.words": [
+ "acpi",
+ "crtc",
+ "efer",
+ "initializable",
+ "interprocedural",
+ "invlpg",
+ "invokable",
+ "iwyu",
+ "kapi",
+ "kstd",
+ "memcmp",
+ "multiboot",
+ "nolintnextline",
+ "rdmsr",
+ "rvalues",
+ "sysret",
+ "teachos",
+ "wrmsr"
+ ]
+} \ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 3b5ae9f..f94098e 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -17,7 +17,8 @@
"-d",
"int,cpu_reset",
"-cdrom",
- "${command:cmake.buildDirectory}/teachos-${command:cmake.buildType}.iso"
+ "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.iso",
+ "2>${workspaceFolder}/qemu-stderr-${command:cmake.buildType}.log"
],
"isBackground": true,
"presentation": {
@@ -52,7 +53,8 @@
"-display",
"curses",
"-cdrom",
- "${command:cmake.buildDirectory}/teachos-${command:cmake.buildType}.iso"
+ "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.iso",
+ "2>${workspaceFolder}/qemu-stderr-${command:cmake.buildType}.log"
],
"isBackground": true,
"presentation": {
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c0e45f8..2343c77 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,18 @@ project("kernel"
LANGUAGES ASM C CXX
)
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules")
+
+include("ElfTransformations")
+include("GenerateBootableIso")
+
+#[============================================================================[
+# Global Build System Options
+#]============================================================================]
+
+option(TEACHOS_ENABLE_LINTING "Enable linting during build" ON)
+option(TEACHOS_GENERATE_DOCS "Generate documentation during build" ON)
+
#[============================================================================[
# Global Build System Configuration
#]============================================================================]
@@ -15,61 +27,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION YES)
-set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules")
-
-set(CMAKE_CXX_STANDARD "20")
+set(CMAKE_CXX_STANDARD "23")
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
-#[============================================================================[
-# Documentation
-#]============================================================================]
-
-find_package("Doxygen")
-
-set(DOXYGEN_GENERATE_HTML YES)
-set(DOXYGEN_GENERATE_XML YES)
-set(DOXYGEN_EXCLUDE_PATTERNS "*.cpp")
-set(DOXYGEN_OUTPUT_DIRECTORY "doxygen")
-set(DOXYGEN_QUIET YES)
-
-file(GLOB_RECURSE DOXYGEN_SOURCES CONFIGURE_DEPENDS "*.hpp")
-
-message(STATUS "${SPHINX_SOURCES}")
-
-doxygen_add_docs("docs_xml"
- ${DOXYGEN_SOURCES}
- ALL
- USE_STAMP_FILE
- COMMENT "Generating developer documentation sources"
-)
-
-set_target_properties("docs_xml" PROPERTIES
- ADDITIONAL_CLEAN_FILES
- "${PROJECT_BINARY_DIR}/doxygen"
-)
-
-file(GLOB_RECURSE SPHINX_SOURCES CONFIGURE_DEPENDS "../docs/**.rst")
-
-add_custom_target("docs" ALL
- COMMAND "${SPHINX_BUILD_EXE}"
- "../docs"
- "docs"
- "-q"
- DEPENDS "docs_xml"
- SOURCES ${SPHINX_SOURCES}
- COMMENT "Generating developer documentation html"
-)
-
-set_target_properties("docs" PROPERTIES
- ADDITIONAL_CLEAN_FILES
- "${PROJECT_BINARY_DIR}/docs"
-)
-
-#[============================================================================[
-# Global Compiler Configuration
-#]============================================================================]
-
add_compile_options(
"$<$<CXX_COMPILER_ID:GNU>:-Wall>"
"$<$<CXX_COMPILER_ID:GNU>:-Wextra>"
@@ -78,83 +39,35 @@ add_compile_options(
)
#[============================================================================[
-# Global Directories
-#]============================================================================]
-
-include_directories(
- "include"
- "arch/${CMAKE_SYSTEM_PROCESSOR}/include"
-)
-
-#[============================================================================[
-# The Bootstrap Library
-#]============================================================================]
-
-add_library("_boot" OBJECT)
-add_library("teachos::boot" ALIAS "_boot")
-
-#[============================================================================[
-# The Video Library
+# Global Linting Configuration
#]============================================================================]
-add_library("_video" OBJECT)
-add_library("teachos::video" ALIAS "_video")
+find_program(CLANG_TIDY_EXE "clang-tidy")
-#[============================================================================[
-# THE Memory Library
-#]============================================================================]
-
-add_library("_memory" OBJECT)
-add_library("teachos::memory" ALIAS "_memory")
+if(CLANG_TIDY_EXE AND TEACHOS_ENABLE_LINTING)
+ set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_EXE}")
+ set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}")
+endif()
#[============================================================================[
-# The Exception handling Library
+# Global Documentation Configuration
#]============================================================================]
-add_library("_exception" OBJECT)
-add_library("teachos::exception" ALIAS "_exception")
+find_package(Doxygen "1.10")
-#[============================================================================[
-# The Context switching Library
-#]============================================================================]
-
-add_library("_context" OBJECT)
-add_library("teachos::context_switching" ALIAS "_context")
-
-add_library("_interrupt_handling" OBJECT)
-add_library("teachos::interrupt_handling" ALIAS "_interrupt_handling")
-# https://forum.osdev.org/viewtopic.php?f=1&t=36712
-# https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-interrupt-function-attribute_002c-x86
-target_compile_options("_interrupt_handling" PRIVATE "-mgeneral-regs-only")
-
-#[============================================================================[
-# The Stub Standard Library
-#]============================================================================]
-
-add_library("_stl" OBJECT)
-add_library("teachos::stl" ALIAS "_stl")
-
-#[============================================================================[
-# The Kernel
-#]============================================================================]
-
-add_executable("_kernel"
- "src/kernel/main.cpp"
-)
-add_executable("teachos::kernel" ALIAS "_kernel")
-
-target_link_libraries("_kernel" PRIVATE
- "teachos::boot"
- "teachos::video"
- "teachos::memory"
- "teachos::exception"
- "teachos::stl"
- "teachos::context_switching"
- "teachos::interrupt_handling"
-)
+if(Doxygen_FOUND AND TEACHOS_GENERATE_DOCS)
+ doxygen_add_docs("docs"
+ ALL
+ COMMENT "Generating documentation"
+ CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile"
+ )
+endif()
#[============================================================================[
-# Platform Specific Components
+# Global Targets
#]============================================================================]
add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}")
+add_subdirectory("kapi")
+add_subdirectory("libs")
+add_subdirectory("kernel") \ No newline at end of file
diff --git a/CMakePresets.json b/CMakePresets.json
index b01208a..fd88d3c 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -2,25 +2,36 @@
"version": 6,
"configurePresets": [
{
- "name": "default",
+ "name": "base",
+ "hidden": true,
"binaryDir": "${sourceDir}/build",
"generator": "Ninja Multi-Config",
- "toolchainFile": "${workspaceFolder}/cmake/Platforms/x86_64.cmake",
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;MinSizeRel",
- "CMAKE_EXPORT_COMPILE_COMMANDS": "YES"
+ "CMAKE_EXPORT_COMPILE_COMMANDS": true,
+ "CMAKE_VERIFY_INTERFACE_HEADER_SETS": true
+ }
+ },
+ {
+ "name": "x86_64",
+ "inherits": "base",
+ "toolchainFile": "cmake/Platforms/x86_64.cmake",
+ "cacheVariables": {
+ "TEACHOS_PLATFORM_FRAME_SIZE": "4096",
+ "TEACHOS_PLATFORM_PAGE_SIZE": "4096",
+ "TEACHOS_PLATFORM_PAGING_LEVELS": "4"
}
}
],
"buildPresets": [
{
- "name": "debug",
- "configurePreset": "default",
+ "name": "x86_64-dbg",
+ "configurePreset": "x86_64",
"configuration": "Debug"
},
{
- "name": "release",
- "configurePreset": "default",
+ "name": "x86_64-rel",
+ "configurePreset": "x86_64",
"configuration": "MinSizeRel"
}
]
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..0a784f0
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2974 @@
+# Doxyfile 1.15.0
+
+# This file describes the settings to be used by the documentation system
+# Doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use Doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use Doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "The TeachOS Kernel"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewers a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "A modern, clean-room, portable kernel"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# With the PROJECT_ICON tag one can specify an icon that is included in the tabs
+# when the HTML document is shown. Doxygen will copy the logo to the output
+# directory.
+
+PROJECT_ICON =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where Doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = build/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES then Doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding Doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise cause
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
+
+CREATE_SUBDIRS = YES
+
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, Doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by Doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, Doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, Doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, Doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES, Doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which Doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where Doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, Doxygen will generate much shorter (but
+# less readable) file names. This can be useful if your file system doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen will interpret the
+# first line (until the first dot, question mark or exclamation mark) of a
+# Javadoc-style comment as the brief description. If set to NO, the Javadoc-
+# style will behave just like regular Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the JAVADOC_BANNER tag is set to YES then Doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by Doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will interpret the first
+# line (until the first dot, question mark or exclamation mark) of a Qt-style
+# comment as the brief description. If set to NO, the Qt-style will behave just
+# like regular Qt-style comments (thus requiring an explicit \brief command for
+# a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# By default Python docstrings are displayed as preformatted text and Doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# Doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as Doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then Doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make Doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by Doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by Doxygen, so you can
+# mix Doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# If the MARKDOWN_STRICT tag is enabled then Doxygen treats text in comments as
+# Markdown formatted also in cases where Doxygen's native markup format
+# conflicts with that of Markdown. This is only relevant in cases where
+# backticks are used. Doxygen's native markup style allows a single quote to end
+# a text fragment started with a backtick and then treat it as a piece of quoted
+# text, whereas in Markdown such text fragment is treated as verbatim and only
+# ends when a second matching backtick is found. Also, Doxygen's native markup
+# format requires double quotes to be escaped when they appear in a backtick
+# section, whereas this is not needed for Markdown.
+# The default value is: YES.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+MARKDOWN_STRICT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 6.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 6
+
+# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
+# generate identifiers for the Markdown headings. Note: Every identifier is
+# unique.
+# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
+# sequence number starting at 0 and GITHUB use the lower case version of title
+# with any whitespace replaced by '-' and punctuation characters removed.
+# The default value is: DOXYGEN.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+MARKDOWN_ID_STYLE = GITHUB
+
+# When enabled Doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO. Words listed in the
+# AUTOLINK_IGNORE_WORDS tag are excluded from automatic linking.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# This tag specifies a list of words that, when matching the start of a word in
+# the documentation, will suppress auto links generation, if it is enabled via
+# AUTOLINK_SUPPORT. This list does not affect links explicitly created using \#
+# or the \link or commands.
+# This tag requires that the tag AUTOLINK_SUPPORT is set to YES.
+
+AUTOLINK_IGNORE_WORDS =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let Doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also makes the inheritance and
+# collaboration diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse
+# them like normal C++ but will assume all classes use public instead of private
+# inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# Doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then Doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, Doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# Doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run Doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+# The NUM_PROC_THREADS specifies the number of threads Doxygen is allowed to use
+# during processing. When set to 0 Doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 512, default value: 1.
+
+NUM_PROC_THREADS = 1
+
+# If the TIMESTAMP tag is set different from NO then each generated page will
+# contain the date or date and time when the page was generated. Setting this to
+# NO can help when comparing the output of multiple runs.
+# Possible values are: YES, NO, DATETIME and DATE.
+# The default value is: NO.
+
+TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_UNDOC_NAMESPACES tag is set to YES, Doxygen will hide all
+# undocumented namespaces that are normally visible in the namespace hierarchy.
+# If set to NO, these namespaces will be included in the various overviews. This
+# option has no effect if EXTRACT_ALL is enabled.
+# The default value is: YES.
+
+HIDE_UNDOC_NAMESPACES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = YES
+
+# With the correct setting of option CASE_SENSE_NAMES Doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and macOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
+
+CASE_SENSE_NAMES = SYSTEM
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then Doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= YES
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then Doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then Doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then Doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then Doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = YES
+
+# If the SORT_GROUP_NAMES tag is set to YES then Doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = YES
+
+# If the STRICT_PROTO_MATCHING option is enabled and Doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING Doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# Doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by Doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by Doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents Doxygen's defaults, run Doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run Doxygen from a directory containing a file called
+# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+# The EXTERNAL_TOOL_PATH tag can be used to extend the search path (PATH
+# environment variable) so that external tools such as latex and gs can be
+# found.
+# Note: Directories specified with EXTERNAL_TOOL_PATH are added in front of the
+# path already specified by the PATH variable, and are added in the order
+# specified.
+# Note: This option is particularly useful for macOS version 14 (Sonoma) and
+# higher, when running Doxygen from Doxywizard, because in this case any user-
+# defined changes to the PATH are ignored. A typical example on macOS is to set
+# EXTERNAL_TOOL_PATH = /Library/TeX/texbin /usr/local/bin
+# together with the standard path, the full search path used by doxygen when
+# launching external tools will then become
+# PATH=/Library/TeX/texbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+
+EXTERNAL_TOOL_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by Doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by Doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then Doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, Doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, Doxygen will warn about incomplete
+# function parameter documentation. If set to NO, Doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, Doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about
+# undocumented enumeration values. If set to NO, Doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
+# If WARN_LAYOUT_FILE option is set to YES, Doxygen will warn about issues found
+# while parsing the user defined layout file, such as missing or wrong elements.
+# See also LAYOUT_FILE for details. If set to NO, problems with the layout file
+# will be suppressed.
+# The default value is: YES.
+
+WARN_LAYOUT_FILE = YES
+
+# If the WARN_AS_ERROR tag is set to YES then Doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then Doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the Doxygen process Doxygen will return with a non-zero status.
+# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then Doxygen behaves
+# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined Doxygen will not
+# write the warning messages in between other messages but write them at the end
+# of a run, in case a WARN_LOGFILE is defined the warning messages will be
+# besides being in the defined file also be shown at the end of a run, unless
+# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
+# the behavior will remain as with the setting FAIL_ON_WARNINGS.
+# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that Doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of Doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = arch \
+ kapi \
+ libs
+
+# This tag can be used to specify the character encoding of the source files
+# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# This tag can be used to specify the character encoding of the source files
+# that Doxygen parses. The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1).
+# See also: INPUT_ENCODING for further information on supported encodings.
+
+INPUT_FILE_ENCODING =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by Doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
+# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
+# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php,
+# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be
+# provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS = *.ipp \
+ *.h \
+ *.hxx \
+ *.hpp \
+ *.hxx \
+ *.dox
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which Doxygen is
+# run.
+
+EXCLUDE = arch/x86_64/pre
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that Doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that Doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by Doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by Doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the Doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+# If the IMPLICIT_DIR_DOCS tag is set to YES, any README.md file found in sub-
+# directories of the project's root, is used as the documentation for that sub-
+# directory, except when the README.md starts with a \dir, \page or \mainpage
+# command. If set to NO, the README.md file needs to start with an explicit \dir
+# command in order to be used as directory documentation.
+# The default value is: YES.
+
+IMPLICIT_DIR_DOCS = YES
+
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER = 72
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# multi-line macros, enums or list initialized variables directly into the
+# documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct Doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of Doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by Doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then Doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which Doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not Doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then Doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by Doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not Doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH = ./build
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, Doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank Doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that Doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that Doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of Doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank Doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that Doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank Doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that Doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by Doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generates light mode output, DARK always
+# generates dark mode output, AUTO_LIGHT automatically sets the mode according
+# to the user preference, uses light mode if no preference is set (the default),
+# AUTO_DARK automatically sets the mode according to the user preference, uses
+# dark mode if no preference is set and TOGGLE allows a user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE = AUTO_LIGHT
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
+# dynamically folded and expanded in the generated HTML source code.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_CODE_FOLDING = YES
+
+# If the HTML_COPY_CLIPBOARD tag is set to YES then Doxygen will show an icon in
+# the top right corner of code and text fragments that allows the user to copy
+# its content to the clipboard. Note this only works if supported by the browser
+# and the web page is served via a secure context (see:
+# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file:
+# protocol.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COPY_CLIPBOARD = YES
+
+# Doxygen stores a couple of settings persistently in the browser (via e.g.
+# cookies). By default these settings apply to all HTML pages generated by
+# Doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store
+# the settings under a project specific key, such that the user preferences will
+# be stored separately.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_PROJECT_COOKIE =
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, Doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then Doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline (the HTML help workshop was already many
+# years in maintenance mode). You can download the HTML help workshop from the
+# web archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by Doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# Doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# The SITEMAP_URL tag is used to specify the full URL of the place where the
+# generated documentation will be placed on the server by the user during the
+# deployment of the documentation. The generated sitemap is called sitemap.xml
+# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
+# is specified no sitemap is generated. For information about the sitemap
+# protocol see https://www.sitemaps.org
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SITEMAP_URL =
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty Doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by Doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has more details information than the tab index, you
+# could consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# When GENERATE_TREEVIEW is set to YES, the PAGE_OUTLINE_PANEL option determines
+# if an additional navigation panel is shown at the right hand side of the
+# screen, displaying an outline of the contents of the main page, similar to
+# e.g. https://developer.android.com/reference If GENERATE_TREEVIEW is set to
+# NO, this option has no effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+PAGE_OUTLINE_PANEL = YES
+
+# When GENERATE_TREEVIEW is set to YES, the FULL_SIDEBAR option determines if
+# the side bar is limited to only the treeview area (value NO) or if it should
+# extend to the full height of the window (value YES). Setting this to YES gives
+# a layout similar to e.g. https://docs.readthedocs.io with more room for
+# contents, but less room for the project logo, title, and description. If
+# GENERATE_TREEVIEW is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# Doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 1
+
+# When the SHOW_ENUM_VALUES tag is set doxygen will show the specified
+# enumeration values besides the enumeration mnemonics.
+# The default value is: NO.
+
+SHOW_ENUM_VALUES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, Doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, Doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# Doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2, MathJax_3 and MathJax_4.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# https://docs.mathjax.org/en/v2.7/output.html), MathJax version 3 (see:
+# https://docs.mathjax.org/en/v3.2/output/index.html) and MathJax version 4
+# (see:
+# https://docs.mathjax.org/en/v4.0/output/index.htm).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. For Mathjax version 2 the
+# destination directory should contain the MathJax.js script. For instance, if
+# the mathjax directory is located at the same level as the HTML output
+# directory, then MATHJAX_RELPATH should be ../mathjax.s For Mathjax versions 3
+# and 4 the destination directory should contain the tex-<format>.js script
+# (where <format> is either chtml or svg). The default value points to the
+# MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax. However, it is strongly recommended to install a local
+# copy of MathJax from https://www.mathjax.org before deployment. The default
+# value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# - in case of MathJax version 4: https://cdn.jsdelivr.net/npm/mathjax@4
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH =
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7/tex.html):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# https://docs.mathjax.org/en/v3.2/input/tex/extensions/):
+# MATHJAX_EXTENSIONS = ams
+# For example for MathJax version 4 (see
+# https://docs.mathjax.org/en/v4.0/input/tex/extensions/):
+# MATHJAX_EXTENSIONS = units
+# Note that for Mathjax version 4 quite a few extensions are already
+# automatically loaded. To disable a package in Mathjax version 4 one can use
+# the package name prepended with a minus sign (- like MATHJAX_EXTENSIONS +=
+# -textmacros)
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces
+# of code that will be used on startup of the MathJax code. See the Mathjax site
+# for more details:
+# - MathJax version 2 (see:
+# https://docs.mathjax.org/en/v2.7/)
+# - MathJax version 3 (see:
+# https://docs.mathjax.org/en/v3.2/)
+# - MathJax version 4 (see:
+# https://docs.mathjax.org/en/v4.0/) For an example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for
+# the HTML output. The underlying search engine uses JavaScript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the JavaScript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, Doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled Doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through Doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, Doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, Doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank Doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that Doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of Doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank Doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that Doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by Doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, Doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
+# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
+# mode nothing is printed on the terminal, errors are scrolled as if <return> is
+# hit at every error; missing files that TeX tries to input or request from
+# keyboard input (\read on a not open input stream) cause the job to abort,
+# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
+# but there is no possibility of user interaction just like in batch mode,
+# SCROLL In scroll mode, TeX will stop only for missing files to input or if
+# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
+# each error, asking for user intervention.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then Doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plainnat.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plainnat
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, Doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, Doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to Doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that Doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to Doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the RTF_OUTPUT output directory.
+# Note that the files will be copied as-is; there are no commands or markers
+# available.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTRA_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, Doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, Doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, Doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, Doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, Doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, Doxygen will generate an
+# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to Sqlite3 output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_SQLITE3 tag is set to YES Doxygen will generate a Sqlite3
+# database with symbols found by Doxygen stored in tables.
+# The default value is: NO.
+
+GENERATE_SQLITE3 = NO
+
+# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
+# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
+# in front of it.
+# The default directory is: sqlite3.
+# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
+
+SQLITE3_OUTPUT = sqlite3
+
+# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db
+# database file will be recreated with each Doxygen run. If set to NO, Doxygen
+# will warn if a database file is already found and not modify it.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
+
+SQLITE3_RECREATE_DB = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, Doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, Doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, Doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, Doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then Doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which Doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, Doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
+# will be listed in the class and namespace index. If set to NO, only the
+# inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the topic index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to diagram generator tools
+#---------------------------------------------------------------------------
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then Doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations Doxygen is allowed
+# to run in parallel. When set to 0 Doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 512, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# Doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
+
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
+
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
+
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then Doxygen will
+# generate a graph for each documented class showing the direct and indirect
+# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
+# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
+# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
+# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
+# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
+# relations will be shown as texts / links. Explicit enabling an inheritance
+# graph or choosing a different representation for an inheritance graph of a
+# specific class, can be accomplished by means of the command \inheritancegraph.
+# Disabling an inheritance graph can be accomplished by means of the command
+# \hideinheritancegraph.
+# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
+# The default value is: YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then Doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes. Explicit enabling a collaboration graph,
+# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
+# command \collaborationgraph. Disabling a collaboration graph can be
+# accomplished by means of the command \hidecollaborationgraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then Doxygen will generate a graph for
+# groups, showing the direct groups dependencies. Explicit enabling a group
+# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
+# of the command \groupgraph. Disabling a directory graph can be accomplished by
+# means of the command \hidegroupgraph. See also the chapter Grouping in the
+# manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, Doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the UML_LOOK tag is enabled, field labels are shown along the edge between
+# two class nodes. If there are many fields and many nodes the graph may become
+# too cluttered. The UML_MAX_EDGE_LABELS threshold limits the number of items to
+# make the size more manageable. Set this to 0 for no limit.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_MAX_EDGE_LABELS = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, Doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, Doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, Doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will be wrapped across multiple lines. Some heuristics are
+# applied to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then Doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
+# can be accomplished by means of the command \includegraph. Disabling an
+# include graph can be accomplished by means of the command \hideincludegraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then Doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
+# to NO, can be accomplished by means of the command \includedbygraph. Disabling
+# an included by graph can be accomplished by means of the command
+# \hideincludedbygraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then Doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then Doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then Doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then Doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories. Explicit enabling a directory graph, when
+# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
+# \directorygraph. Disabling a directory graph can be accomplished by means of
+# the command \hidedirectorygraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# https://www.graphviz.org/)).
+#
+# Note the formats svg:cairo and svg:cairo:cairo cannot be used in combination
+# with INTERACTIVE_SVG (the INTERACTIVE_SVG will be set to NO).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus,
+# png:gdiplus:gdiplus, svg:cairo, svg:cairo:cairo, svg:svg, svg:svg:core,
+# gif:cairo, gif:cairo:gd, gif:cairo:gdiplus, gif:gdiplus, gif:gdiplus:gdiplus,
+# gif:gd, gif:gd:gd, jpg:cairo, jpg:cairo:gd, jpg:cairo:gdiplus, jpg:gd,
+# jpg:gd:gd, jpg:gdiplus and jpg:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg or svg:svg or svg:svg:core, then this option
+# can be set to YES to enable generation of interactive SVG images that allow
+# zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+#
+# Note This option will be automatically disabled when DOT_IMAGE_FORMAT is set
+# to svg:cairo or svg:cairo:cairo.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# You can include diagrams made with dia in Doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using PlantUML, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using PlantUML, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for PlantUML.
+
+PLANTUML_CFG_FILE =
+
+# When using PlantUML, the specified paths are searched for files specified by
+# the !include statement in a PlantUML block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The PLANTUMLFILE_DIRS tag can be used to specify one or more directories that
+# contain PlantUml files that are included in the documentation (see the
+# \plantumlfile command).
+
+PLANTUMLFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, Doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES Doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the Doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, Doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP = YES
+
+# You can define message sequence charts within Doxygen comments using the \msc
+# command. If the MSCGEN_TOOL tag is left empty (the default), then Doxygen will
+# use a built-in version of mscgen tool to produce the charts. Alternatively,
+# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
+# specifying prog as the value, Doxygen will call the tool as prog -T
+# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
+# output file formats "png", "eps", "svg", and "ismap".
+
+MSCGEN_TOOL =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt
index 57b3a60..54f04cb 100644
--- a/arch/x86_64/CMakeLists.txt
+++ b/arch/x86_64/CMakeLists.txt
@@ -1,155 +1,49 @@
-#[============================================================================[
-# The Kernel Library
-#]============================================================================]
+add_library("x86_64" OBJECT)
+add_library("os::arch" ALIAS "x86_64")
-set(TEACHOS_KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld")
-mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT)
-
-target_sources("_kernel" PRIVATE
- "src/kernel/main.cpp"
- "src/kernel/cpu/control_register.cpp"
- "src/kernel/cpu/gdtr.cpp"
- "src/kernel/cpu/idtr.cpp"
- "src/kernel/cpu/if.cpp"
- "src/kernel/cpu/call.cpp"
- "src/kernel/cpu/msr.cpp"
- "src/kernel/cpu/segment_register.cpp"
- "src/kernel/cpu/tlb.cpp"
- "src/kernel/cpu/tr.cpp"
-)
-
-target_link_options("_kernel" PRIVATE
- "-T${TEACHOS_KERNEL_LINKER_SCRIPT}"
+target_include_directories("x86_64" PUBLIC
+ "include"
)
-set_target_properties("_kernel" PROPERTIES
- LINK_DEPENDS "${TEACHOS_KERNEL_LINKER_SCRIPT}"
+target_link_libraries("x86_64" PUBLIC
+ "os::kapi"
+ "libs::multiboot2"
)
-#[============================================================================[
-# The Bootstrap Library
-#]============================================================================]
+target_sources("x86_64" PRIVATE
+ # Low-level bootstrap
+ "src/boot/boot32.S"
+ "src/boot/entry64.s"
+ "src/boot/initialize_runtime.cpp"
+ "src/boot/multiboot.s"
-target_sources("_boot" PRIVATE
- "src/boot/boot.s"
- "src/boot/crti.s"
- "src/boot/crtn.s"
- "src/boot/multiboot.s"
-)
+ # api::kapi implementation
+ "src/kapi/cio.cpp"
+ "src/kapi/cpu.cpp"
+ "src/kapi/memory.cpp"
-#[============================================================================[
-# The Video Library
-#]============================================================================]
+ # Memory management
+ "src/memory/kernel_mapper.cpp"
+ "src/memory/mmu.cpp"
+ "src/memory/page_table.cpp"
+ "src/memory/paging_root.cpp"
+ "src/memory/recursive_page_mapper.cpp"
+ "src/memory/region_allocator.cpp"
+ "src/memory/scoped_mapping.cpp"
-target_sources("_video" PRIVATE
- "src/video/vga/text.cpp"
+ # VGA text mode
+ "src/vga/text.cpp"
)
-#[============================================================================[
-# The Memory Library
-#]============================================================================]
+file(GLOB_RECURSE ARCH_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp")
-target_sources("_memory" PRIVATE
- "src/memory/main.cpp"
- "src/memory/multiboot/elf_symbols_section.cpp"
- "src/memory/multiboot/reader.cpp"
- "src/memory/allocator/area_frame_allocator.cpp"
- "src/memory/allocator/tiny_frame_allocator.cpp"
- "src/memory/allocator/physical_frame.cpp"
- "src/memory/paging/page_entry.cpp"
- "src/memory/paging/page_table.cpp"
- "src/memory/paging/temporary_page.cpp"
- "src/memory/paging/virtual_page.cpp"
- "src/memory/paging/active_page_table.cpp"
- "src/memory/paging/inactive_page_table.cpp"
- "src/memory/heap/bump_allocator.cpp"
- "src/memory/heap/user_heap_allocator.cpp"
- "src/memory/heap/memory_block.cpp"
- "src/memory/heap/linked_list_allocator.cpp"
- "src/memory/heap/global_heap_allocator.cpp"
+target_sources("x86_64" PUBLIC
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES ${ARCH_HEADERS}
)
-#[============================================================================[
-# The STL Library
-#]============================================================================]
-
-target_sources("_stl" PRIVATE
- "src/stl/mutex.cpp"
-)
-
-#[============================================================================[
-# The Exception handling Library
-#]============================================================================]
-
-target_sources("_exception" PRIVATE
- "src/exception_handling/assert.cpp"
- "src/exception_handling/abort.cpp"
- "src/exception_handling/panic.cpp"
- "src/exception_handling/pure_virtual.cpp"
-)
-
-#[============================================================================[
-# The Context switching Library
-#]============================================================================]
-
-target_sources("_context" PRIVATE
- "src/context_switching/segment_descriptor_table/access_byte.cpp"
- "src/context_switching/segment_descriptor_table/gdt_flags.cpp"
- "src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp"
- "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp"
- "src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp"
- "src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp"
- "src/context_switching/main.cpp"
- "src/context_switching/syscall/main.cpp"
- "src/context_switching/syscall/syscall_enable.cpp"
- "src/context_switching/syscall/syscall_handler.cpp"
- "src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp"
- "src/context_switching/interrupt_descriptor_table/idt_flags.cpp"
- "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp"
- "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp"
- "src/context_switching/interrupt_descriptor_table/ist_offset.cpp"
- "src/context_switching/interrupt_descriptor_table/segment_selector.cpp"
+set(KERNEL_LINKER_SCRIPT
+ "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld"
+ PARENT_SCOPE
)
-
-#[============================================================================[
-# The Interrupt Handlers
-#]============================================================================]
-
-target_sources("_interrupt_handling" PRIVATE
- "src/interrupt_handling/generic_interrupt_handler.cpp"
-)
-
-#[============================================================================[
-# The User code
-#]============================================================================]
-
-target_sources("_context" PRIVATE
- "src/user/main.cpp"
-)
-
-#[============================================================================[
-# The Bootable ISO Image
-#]============================================================================]
-
-find_package("grub-mkrescue")
-
-if(grub-mkrescue_FOUND)
- file(GENERATE
- OUTPUT "isofs/boot/grub/grub.cfg"
- INPUT "support/grub.cfg.in"
- )
-
- add_custom_target("bootable-iso"
- COMMAND "${GRUB_MKRESCUE_EXE}"
- "-o"
- "${PROJECT_BINARY_DIR}/teachos-$<CONFIGURATION>.iso"
- "${CMAKE_CURRENT_BINARY_DIR}/isofs"
- "$<TARGET_FILE:teachos::kernel>"
- "2>/dev/null"
- DEPENDS
- "$<TARGET_FILE:teachos::kernel>"
- "isofs/boot/grub/grub.cfg"
- BYPRODUCTS "${PROJECT_BINARY_DIR}/teachos-$<CONFIGURATION>.iso"
- COMMENT "Creating bootable ISO image"
- )
-endif()
diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp
deleted file mode 100644
index fe9c657..0000000
--- a/arch/x86_64/include/arch/boot/pointers.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP
-#define TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP
-
-#include <cstddef>
-
-namespace teachos::arch::boot
-{
- /**
- * @brief Address pointing to the start of the multiboot information structure.
- */
- extern "C" size_t const multiboot_information_pointer;
-
-} // namespace teachos::arch::boot
-
-#endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP
diff --git a/arch/x86_64/include/arch/io/port_io.hpp b/arch/x86_64/include/arch/io/port_io.hpp
deleted file mode 100644
index ba41660..0000000
--- a/arch/x86_64/include/arch/io/port_io.hpp
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP
-#define TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP
-
-#include <concepts>
-#include <cstddef>
-#include <cstdint>
-#include <type_traits>
-
-namespace teachos::arch::io
-{
- /**
- * @brief An I/O port of a given size at a given address.
- *
- * @tparam Address The address (port number) of the I/O port.
- * @tparam Size The size (in bytes) of the I/O port.
- */
- template<std::uint16_t Address, std::size_t Size>
- struct port
- {
- static_assert(Size == 1 || Size == 2 || Size == 4, "A port must be either 1, 2, or 4 bytes in size");
-
- /**
- * @brief The type of data available for reading and writing through this port.
- */
- using io_type =
- std::conditional_t<Size == 1, std::byte, std::conditional_t<Size == 2, std::uint16_t, std::uint32_t>>;
-
- /**
- * @brief Write a byte to the I/O port.
- *
- * @param data The data to write to the I/O port.
- */
- auto static write(io_type data) -> void
- requires(Size == 1)
- {
- asm volatile("mov %[port], %%dx\n"
- "mov %[data], %%al\n"
- "out %%al, %%dx\n"
- :
- : [port] "i"(Address), [data] "im"(data)
- : "dx", "al");
- }
-
- /**
- * @brief Write a word to the I/O port.
- *
- * @param data The data to write to the I/O port.
- */
- auto static write(io_type data) -> void
- requires(Size == 2)
- {
- asm volatile("mov %[port], %%dx\n"
- "mov %[data], %%ax\n"
- "out %%ax, %%dx\n"
- :
- : [port] "i"(Address), [data] "im"(data)
- : "dx", "ax");
- }
-
- /**
- * @brief Write a double-word to the I/O port.
- *
- * @param data The data to write to the I/O port.
- */
- auto static write(io_type data) -> void
- requires(Size == 4)
- {
- asm volatile("mov %[port], %%dx\n"
- "mov %[data], %%eax\n"
- "out %%eax, %%dx\n"
- :
- : [port] "i"(Address), [data] "im"(data)
- : "dx", "eax");
- }
-
- /**
- * @brief Read a byte from the I/O port.
- *
- * @return The data read from the I/O port.
- */
- auto static read() -> io_type
- requires(Size == 1)
- {
- auto data = io_type{};
- asm volatile("mov %[port], %%dx\n"
- "in %%dx, %%al\n"
- "mov %%al, %[data]\n"
- : [data] "=m"(data)
- : [port] "i"(Address)
- : "dx", "al");
- return data;
- }
-
- /**
- * @brief Read a word from the I/O port.
- *
- * @return The data read from the I/O port.
- */
- auto static read() -> io_type
- requires(Size == 2)
- {
- auto data = io_type{};
- asm volatile("mov %[port], %%dx\n"
- "in %%dx, %%ax\n"
- "mov %%ax, %[data]\n"
- : [data] "=m"(data)
- : [port] "i"(Address)
- : "dx", "ax");
- return data;
- }
-
- /**
- * @brief Read a double-word from the I/O port.
- *
- * @return The data read from the I/O port.
- */
- auto static read() -> io_type
- requires(Size == 4)
- {
- auto data = io_type{};
- asm volatile("mov %[port], %%dx\n"
- "in %%dx, %%eax\n"
- "mov %%eax, %[data]\n"
- : [data] "=m"(data)
- : [port] "i"(Address)
- : "dx", "eax");
- return data;
- }
- };
-
-} // namespace teachos::arch::io
-
-#endif // TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP
diff --git a/arch/x86_64/include/arch/kernel/cpu/control_register.hpp b/arch/x86_64/include/arch/kernel/cpu/control_register.hpp
deleted file mode 100644
index dcaf02d..0000000
--- a/arch/x86_64/include/arch/kernel/cpu/control_register.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP
-#define TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP
-
-#include <cstdint>
-
-namespace teachos::arch::kernel::cpu
-{
- /**
- * @brief Control registers that can be read and written to.
- *
- * @note CR1 and CR5 - 7 are reserved and will throw an exception if they are accessed, therefore they are not defined
- * in the enum. See https://en.wikipedia.org/wiki/Control_register#Control_registers_in_Intel_x86_series for more
- * information.
- */
- enum struct control_register : uint8_t
- {
- CR0, ///< Contains various control flags that modify basic operation of the processor, Machine Status World (MSW)
- ///< register.
- CR2 = 2U, ///< Contains Page Fault Linear Address (PFLA), when page fault occurs address program attended to accces
- ///< is stored here.
- CR3, ///< Enables process to translate linear addresses into physical addresses using paging, CR0 bit 32 Paging
- ///< (PG) needs to be enabled simply contains the register value that represents the physical address of the
- ///< level 4 page table used for paging in the system. Therefore reading this value allows to access the level
- ///< 4 page table directly. Instead of over the virtual address 0xffffffff'fffff000, which then has to be
- ///< first translated into a physical address.
- CR4 ///< Used in protected mode to control operations.
- };
-
- /**
- * @brief Control register 0 flags that can be set.
- *
- * @note Modifies the basic operation of the processor. Only the most important extensions are listed below, the rest
- * are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#CR0 for more information.
- */
- enum struct cr0_flags : uint64_t
- {
- PROTECTED_MODE_ENABLED = 1U << 0U, ///< System is in protected or system is in real mode.
- TASK_SWITCHED = 1U << 3U, ///< Allows saving x87 task context upon a task switch only after x87 instruction used.
- WRITE_PROTECT = 1U << 16U, ///< When set, the CPU cannot write to read-only pages when privilege level is 0.
- PAGING = 1U << 31U, // Enable paging using the CR3 register.
- };
-
- /**
- * @brief Reads the value of the given control register.
- *
- * @param cr Control register that should be read.
- * @return Value of the control register.
- */
- auto read_control_register(control_register cr) -> uint64_t;
-
- /**
- * @brief Sets a specific bit in the Extended Feature Enable Register (EFER) Model-Specific Register (MSR) register.
- *
- * @param cr Control register that should be written.
- * @param new_value New value that should be written.
- */
- auto write_control_register(control_register cr, uint64_t new_value) -> void;
-
- /**
- * @brief Sets a specific bit in the CR0.
- *
- * @note This function reads the current value of the CR0 register, ORs the specified
- * bit with the current value, and writes the updated value back to the CR0.
- *
- * @param flag he flag to set in the CR0.
- */
- auto set_cr0_bit(cr0_flags flag) -> void;
-
-} // namespace teachos::arch::kernel::cpu
-
-#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP
diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
deleted file mode 100644
index 6cb5f56..0000000
--- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP
-
-#include "arch/memory/allocator/physical_frame.hpp"
-#include "arch/memory/multiboot/reader.hpp"
-
-#include <optional>
-
-namespace teachos::arch::memory::allocator
-{
- /**
- * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any
- * deallocated frames.
- */
- struct area_frame_allocator
- {
- /**
- * @brief Constructor.
- *
- * @param mem_info Structure containg all relevant information to map and allocate memory.
- */
- area_frame_allocator(multiboot::memory_information const & mem_info);
-
- /**
- * @brief Allocate memory by finding and returning a free physical frame.
- *
- * @note The physical_frame allocation executes multiple checks before returning
- * the physical_frame that is available to allocate. It must at least
- * do the following:
- * - check if the next_free_frame is within the current_area
- * - check if the next_free_frame is actually free
- * - update the next_free_frame after finding a free physical_frame
- *
- * @return next free physical frame or nullopt if none was found.
- */
- auto allocate_frame() -> std::optional<physical_frame>;
-
- /**
- * @brief Deallocates a previously allocated physical frame.
- *
- * @note Simply does nothing, because the simply area frame
- * allocator implementation does not keep track of free or used frames and can therefore not deallocate, because it
- * does not know which frames have been alocated in the first place.
- *
- * @param physical_frame Previously allocated physical_frame that should be deallocated.
- */
- auto deallocate_frame(physical_frame const & physical_frame) -> void;
-
- private:
- /**
- * @brief Find the next memory area and write it into current_area.
- */
- auto choose_next_area() -> void;
-
- physical_frame next_free_frame; ///< The physical_frame after the last allocated one.
- std::optional<multiboot::memory_area> current_area; ///< The current memory area.
- multiboot::memory_area_container const
- memory_areas; ///< All memory areas in custom container allows to use std::ranges.
- physical_frame const kernel_start; ///< The start address of the kernel code in memory.
- physical_frame const kernel_end; ///< The end address of the kernel code in memory.
- physical_frame const multiboot_start; ///< The start address of the multiboot code in memory.
- physical_frame const multiboot_end; ///< The end address of the multiboot code in memory.
- };
-
-} // namespace teachos::arch::memory::allocator
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP
diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp
deleted file mode 100644
index 2d3f4ae..0000000
--- a/arch/x86_64/include/arch/memory/allocator/concept.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP
-
-#include "arch/memory/allocator/physical_frame.hpp"
-
-#include <optional>
-
-namespace teachos::arch::memory::allocator
-{
- /**
- * @brief Frame allocator concept required for allocating and deallocating physical frames in memory.
- */
- template<typename T>
- concept FrameAllocator = requires(T t, physical_frame const & a) {
- { t.allocate_frame() } -> std::same_as<std::optional<physical_frame>>;
- { t.deallocate_frame(a) } -> std::same_as<void>;
- };
-
-} // namespace teachos::arch::memory::allocator
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP
diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp
deleted file mode 100644
index cb6c5b3..0000000
--- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP
-
-#include "arch/stl/container.hpp"
-#include "arch/stl/forward_value_iterator.hpp"
-
-#include <compare>
-#include <cstdint>
-#include <iterator>
-
-namespace teachos::arch::memory::allocator
-{
- using physical_address = std::size_t;
-
- std::size_t constexpr PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB.
-
- /**
- * @brief Specific physical frame containing helper functions to determine if a specific address is in that
- * physical frame or not.
- */
- struct physical_frame
- {
- /**
- * @brief Defaulted constructor.
- */
- constexpr physical_frame() = default;
-
- /**
- * @brief Constructor.
- *
- * @param frame_number Index number that should be assigned to this physical frame.
- */
- explicit constexpr physical_frame(std::size_t frame_number)
- : frame_number(frame_number)
- {
- // Nothing to do
- }
-
- /**
- * @brief Returns the physical frame the given address is contained in.
- *
- * @param address Physical address we want to get the corresponding physical frame for.
- * @return Frame the given address is contained in.
- */
- auto static containing_address(physical_address address) -> physical_frame;
-
- /**
- * @brief Get the start address of this physical frame.
- *
- * @return Start address of the physical frame.
- */
- auto start_address() const -> physical_address;
-
- /**
- * @brief Post increment operator. Returns a copy of the value.
- *
- * @return Copy of the incremented underlying frame number.
- */
- auto operator++(int) -> physical_frame;
-
- /**
- * @brief Pre increment operator. Returns a reference to the changed value.
- *
- * @return Reference to the incremented underlying frame number.
- */
- auto operator++() -> physical_frame &;
-
- /**
- * @brief Defaulted equals operator.
- */
- auto operator==(physical_frame const & other) const -> bool = default;
-
- /**
- * @brief Defaulted three-way comparsion operator.
- */
- auto operator<=>(physical_frame const & other) const -> std::partial_ordering = default;
-
- std::size_t frame_number =
- {}; ///< Index number of the current physical frame, used to distinguish it from other frames.
- };
-
- using frame_container = stl::container<stl::forward_value_iterator<physical_frame>>;
-
-} // namespace teachos::arch::memory::allocator
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP
diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp
deleted file mode 100644
index 1ceb74d..0000000
--- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP
-
-#include "arch/memory/allocator/concept.hpp"
-#include "arch/memory/allocator/physical_frame.hpp"
-
-#include <array>
-
-namespace teachos::arch::memory::allocator
-{
- namespace
- {
- uint8_t constexpr TINY_ALLOCATOR_FRAMES_COUNT = 3U;
- }
-
- /**
- * @brief Allocates memory using memory areas read from the multiboot2 information pointer. Does not allocate its own
- * frames, but uses the necessary three frames provided by another allocator to map one virtual level 1 page entry and
- * the necessary upper layers.
- */
- struct tiny_frame_allocator
- {
- /**
- * @brief Constructor.
- *
- * @tparam T Contract the allocator that should be used to actually allocate and deallocate, the underlying three
- * frames has to follow.
- *
- * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate
- * entries when the underlying frames are created.
- */
- template<allocator::FrameAllocator T>
- tiny_frame_allocator(T & allocator)
- : frames{}
- {
- // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(),
- // does not work because it would set the value correctly but because we pass it as an std::optional it would not
- // set the engaged flag. Meaning the has_value() method would still return false.
- for (auto & frame : frames)
- {
- auto allocated = allocator.allocate_frame();
- if (allocated.has_value())
- {
- frame.emplace(allocated.value());
- }
- }
- }
-
- /**
- * @brief Allocate memory by finding and returning one of the three free physical frames.
- *
- * @return First free physical frames of the three frames held by this allocator or nullopt if we used up all three
- * frames already.
- */
- auto allocate_frame() -> std::optional<physical_frame>;
-
- /**
- * @brief Deallocates one of the three previously allocated physical frames.
- *
- * @note If more than the three frames are deallocated the method will halt execution, because it can only hold 3
- * frames.
- *
- * @param physical_frame Previously allocated physical_frame that should be deallocated.
- */
- auto deallocate_frame(physical_frame const & physical_frame) -> void;
-
- private:
- std::array<std::optional<physical_frame>, TINY_ALLOCATOR_FRAMES_COUNT> frames =
- {}; ///< Container that holds the frames allocated by another allocator.
- };
-
-} // namespace teachos::arch::memory::allocator
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP
diff --git a/arch/x86_64/include/arch/memory/main.hpp b/arch/x86_64/include/arch/memory/main.hpp
deleted file mode 100644
index d51815f..0000000
--- a/arch/x86_64/include/arch/memory/main.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP
-
-#include "arch/memory/paging/page_entry.hpp"
-
-#include <cstdint>
-
-namespace teachos::arch::memory
-{
-
- /**
- * @brief Maps a heap section to a page.
- *
- * @param heap_start Start-address of the heap.
- * @param heap_size Size of the heap.
- * @param additional_flags Additional flags to apply to the page entry.
- */
- auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags) -> void;
-
- /**
- * @brief Initializes memory management.
- *
- * @note Enables the necessary register flags and remaps the kernel,
- * elf_sections, vga_text and the heap.
- */
- auto initialize_memory_management() -> void;
-
-} // namespace teachos::arch::memory
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP
diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp
deleted file mode 100644
index 0a25ca9..0000000
--- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp
+++ /dev/null
@@ -1,169 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP
-
-#include "arch/memory/multiboot/info.hpp"
-#include "arch/stl/container.hpp"
-#include "arch/stl/contiguous_pointer_iterator.hpp"
-
-#include <bitset>
-#include <cstdint>
-
-namespace teachos::arch::memory::multiboot
-{
- /**
- * @brief Defines all elf section types an elf section header can have.
- *
- * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information.
- */
- enum struct elf_section_type : uint32_t
- {
- INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out.
- PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE).
- SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table.
- STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and debugging null-terminated strings.
- RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems.
- SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols.
- DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information.
- NOTE, ///< (SHT_NOTE) Stores information that marks files in some way.
- EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss).
- RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems.
- UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics.
- DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking.
- INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void.
- TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void.
- PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other
- ///< initalization functions () -> void.
- };
-
- /**
- * @brief Defines helper function for all states that the elf section flags of an elf section header can
- * have.
- *
- * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information.
- */
- struct elf_section_flags
- {
- /**
- * @brief Possible set bits in our underlying std::bitset and the meaning when they are set.
- */
- enum bitset : uint32_t
- {
- WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section
- ///< is assumed to be READONLY and only that flag is shown in the objdump.
- OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution.
- ///< ALLOC flag is shown in the objdump.
- EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump.
- DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section.
- CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings.
- SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX =
- 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info)
- ///< additional_information variable.
- PRESERVE_ORDERING_AFTER_COMBINATION =
- 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section.
- REQUIRES_SPECIAL_OS_PROCESSING =
- 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or
- ///< data, which does not confirm to standard ELF specifications.
- SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group.
- HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data.
- COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data.
- SPECIAL_ORDERING_REQUIREMENTS =
- 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it
- ///< should be ordered in relation to other sections of the same type.
- EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or
- ///< allocated, used for LTO (Link-Time Optimizations).
- };
-
- /**
- * @brief Constructor.
- *
- * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to
- * allow reading the state of single bits more easily.
- */
- explicit elf_section_flags(uint64_t flags)
- : flags(flags)
- {
- // Nothing to do
- }
-
- /**
- * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset.
- *
- * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng
- * std::bitset. Any additional bits that are set are not relevant.
- *
- * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set.
- * @return Whether the given flags are a subset or equivalent with the underlying std::bitset.
- */
- auto contains_flags(std::bitset<64U> other) const -> bool;
-
- /**
- * @brief Allows to compare the underlying std::bitset of two instances.
- *
- * @param other Other instance that we want to compare with.
- * @return Whether the underlying std::bitset of both types is the same.
- */
- auto operator==(elf_section_flags const & other) const -> bool = default;
-
- private:
- std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating
- ///< system specific semantics and bits 29 - 32 are reserved for processor specific
- ///< semantics. Bits 33 - 64 are unused for compatability with ELF32.
- };
-
- /**
- * @brief Defines the data included in a section header, where each section has exactly one section header.
- *
- * @note See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information.
- */
- struct elf_section_header
- {
- uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section.
- elf_section_type type; ///< Categorizes the sections content and semantics.
- elf_section_flags flags; ///< 1-bit flgas that describe section attributes.
- uint64_t physical_address; ///< If section appears in memory image of a process, gives address at which the
- ///< sections first byte should reside, otherwise 0.
- uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS
- ///< contains the conceptual placement instead (because it occupies no space in the file).
- uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always
- ///< occupy no space in the file.
- uint32_t other_section; ///< Section header table index link, behaviour varies on type
- ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link.
- uint32_t additional_information; ///< Extra information, behaviour varies on type
- ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link.
- uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value
- ///< of address_alignment. Value 0 or 1 mean no alignment constraints.
- uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in
- ///< bytes of each entry.
-
- /**
- * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the
- * sections table.
- *
- * @return Whether the current section header is actually null or not, requires all fields besides section_size and
- * other_section to contain 0.
- */
- auto is_null() const -> bool;
- };
-
- /**
- * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type
- * multi_boot_tag_type::ELF_SECTIONS.
- *
- * @note The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section
- * and only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE.
- */
- struct elf_symbols_section_header
- {
- tag info; ///< Basic multi_boot_tag information.
- uint32_t number_of_sections; ///< Number of sections in the sections array.
- uint32_t entry_size; ///< Size of each entry in the sections array.
- uint32_t section_index; ///< Index to the string table used for symbol names.
- std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data.
- ///< contained in the section, to ensure byte alignment is actually 4 byte.
- };
-
- using elf_section_header_container = stl::container<stl::contiguous_pointer_iterator<elf_section_header>>;
-
-} // namespace teachos::arch::memory::multiboot
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP
diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp
deleted file mode 100644
index 68394c8..0000000
--- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP
-
-#include "arch/memory/multiboot/info.hpp"
-#include "arch/stl/container.hpp"
-#include "arch/stl/contiguous_pointer_iterator.hpp"
-
-#include <cstdint>
-
-namespace teachos::arch::memory::multiboot
-{
- /**
- * @brief Defines all memory area types possible that the memory region can be in.
- */
- enum struct memory_area_type : uint32_t
- {
- AVAILABLE = 1, ///< Region is available for use by the OS.
- RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS.
- ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event.
- RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS).
- DEFECTIVE ///< Region is defective or unusable.
- };
-
- /**
- * @brief Defines an entry in the entries array of the memory_map struct.
- *
- * @note Last value needs to be padded, because the size of the entry needs to be
- * exactly 24 bytes and not one byte more.
- */
- struct memory_area
- {
- uint64_t base_address; ///< Base address the memory region starts at.
- uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address.
- alignas(8) memory_area_type type; ///< Specific type of memory the region can contain.
- };
-
- /**
- * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type
- * multi_boot_tag_type::MEMORY_MAP.
- */
- struct memory_map_header
- {
- tag info; ///< Basic multi_boot_tag information.
- uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8.
- uint32_t entry_version; ///< Version of the entries, currently 0.
- struct memory_area entries; ///< Specific memory regions.
- };
-
- using memory_area_container = stl::container<stl::contiguous_pointer_iterator<memory_area>>;
-
-} // namespace teachos::arch::memory::multiboot
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP
diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp
deleted file mode 100644
index bda0c43..0000000
--- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP
-
-#include "arch/memory/multiboot/elf_symbols_section.hpp"
-#include "arch/memory/multiboot/memory_map.hpp"
-
-#include <cstdint>
-
-namespace teachos::arch::memory::multiboot
-{
- /**
- * @brief Contains all relevant information to map and allocate memory that is read from the multiboot2 information
- * structure.
- */
- struct memory_information
- {
- std::size_t kernel_start; ///< Start address of the kernel code in memory.
- std::size_t kernel_end; ///< End address of the kernel code in memory.
- elf_section_header_container sections; ///< Contains non-owning pointers to all kernel sections.
- std::size_t multiboot_start; ///< Start address of the multiboot code in memory.
- std::size_t multiboot_end; ///< End address of the multiboot code in memory.
- memory_area_container areas; ///< Contains non-owning pointers to all memory areas.
- };
-
- /**
- * @brief Reads the relevant multiboot2 information data from memory.
- *
- * @note This is done using the multiboot_information_pointer, which marks the start of the multiboot2 data. The
- * indivdual headers we have to read are 8 byte aligned, whereas the data contained in those headers does not have to
- * be. All sections that are read additionaly receive some sanity to ensure the read address is actually pointing to
- * the expected structure, if they are not this method will assert.
- *
- * The memory_information variables are calcualted like this:
- * - kernel_start: Calculated by getting the lowest address specified in the elf symbols headers.
- * - kernel_end: Calculated by getting the highest address specified in the elf symbols headers and adding the length
- * of that section.
- * - multiboot_start: Calcualted by simply getting the value of the multiboot information pointer, because it already
- * contains the address pointint to the start of the multiboot2 data.
- * - multiboot_end: Calcualted by getting the value of the multiboot information pointer and adding the total size of
- * the complete multiboot2 data
- * - memory_areas: Calculated by simply accessing the address of the entries variable in the memory map header
- * structure.
- * - area_count: Calculated by subtracing the memory map header size from the total tag size, which results in the
- * remaining size (size of the entries array), this size is then divided by the size of one entry in that array, which
- * should be 24 bytes.
- *
- * @return Relevant data read from multiboot2.
- */
- auto read_multiboot2() -> memory_information;
-
-} // namespace teachos::arch::memory::multiboot
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP
diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp
deleted file mode 100644
index f68d8b6..0000000
--- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp
+++ /dev/null
@@ -1,206 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP
-
-#include "arch/exception_handling/assert.hpp"
-#include "arch/kernel/cpu/tlb.hpp"
-#include "arch/memory/allocator/concept.hpp"
-#include "arch/memory/paging/virtual_page.hpp"
-
-#include <array>
-#include <bitset>
-#include <optional>
-
-namespace teachos::arch::memory::paging
-{
- /**
- * @brief Currently actively by the CPU used level 4 page table, is used to ensure there is only ever one valid
- * instance and it cannot be copied or constructed again.
- */
- struct active_page_table
- {
- /**
- * @brief Creates a single instance of an active level 4 page table table and returns the created instance or
- * alternatively returns the previously created instance instead. The instance is owned by this method and is
- * static, meaning it lives on for the complete lifetime of the program.
- *
- * @return Active single unique instance of the level 4 page table.
- */
- static auto create_or_get() -> active_page_table &;
-
- /**
- * @brief Index operator overload to access specific mutable entry directy of the level 4 page table.
- *
- * @param index Index of the entry we want to access and only read.
- * @return Entry at the given table index.
- */
- auto operator[](std::size_t index) -> entry &;
-
- /**
- * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood.
- *
- * @param address Virtual address we want to translate into physical one.
- * @return Physical address corresponding to the provided virtual address.
- */
- auto translate_address(virtual_address address) -> std::optional<allocator::physical_address>;
-
- /**
- * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if
- * it failed attempt to parse using huge pages.
- *
- * @param page Page to translate into physical frame.
- * @return Physical frame corresponding to the provided virtual page.
- */
- auto translate_page(virtual_page page) -> std::optional<allocator::physical_frame>;
-
- /**
- * @brief Translates huge page into actual physical frame.
- *
- * @param page Page to translate into physical frame.
- * @return Physical frame corresponding to the provided virtual page.
- */
- auto translate_huge_page(virtual_page page) -> std::optional<allocator::physical_frame>;
-
- /**
- * @brief Maps a virtual page to a physical frame in the page table with the specified flags.
- *
- * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1
- * page table already exists it halts execution instead.
- *
- * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and
- * deallocate method.
- * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate
- * entries when a new page table is required.
- * @param page Virtual page that is being mapped.
- * @param frame Physical frame that the virtual page will be mapped to.
- * @param flags A bitset of flags that configure the page table entry for this mapping.
- */
- template<allocator::FrameAllocator T>
- auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, std::bitset<64U> flags)
- -> void
- {
- auto current_handle = active_handle;
-
- for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level)
- {
- current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level), flags);
- }
-
- auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)];
- arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE),
- "[Page Mapper] Unable to map huge pages");
- arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used");
- level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT);
- }
-
- /**
- * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame.
- *
- * @see map_page_to_frame
- */
- template<allocator::FrameAllocator T>
- auto map_page_to_next_free_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void
- {
- auto const frame = allocator.allocate_frame();
- exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception");
- map_page_to_frame(allocator, page, frame.value(), flags);
- }
-
- /**
- * @brief Gets the corresponding page the given frame has to be contained in and uses that to call
- * map_page_to_frame.
- *
- * @see map_page_to_frame
- */
- template<allocator::FrameAllocator T>
- auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void
- {
- auto const page = virtual_page::containing_address(frame.start_address());
- map_page_to_frame(allocator, page, frame, flags);
- }
-
- /**
- * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags.
- *
- * @note For the unmap function to deallocates and unmaps correctly, the entry in every page level if this page was
- * the last one up to level 4 should be unmapped and ensured to clear the Translation Lookaside Buffer, so that the
- * unmapped value is removed from cache as well. This is currently not done and instead we only dallocate and unmap
- * the level 1 page table entry, this is the case because it conflicts with our recursive mapping for the temporary
- * page, which requires the other page table entries to walk to the actual level 4 page table. If we remove all page
- * table entries beforehand, we therefore can not remap the kernel anymore.
- *
- * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and
- * deallocate method.
- * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate
- * entries when a new page table is required.
- * @param page Virtual page that is being unmapped.
- */
- template<allocator::FrameAllocator T>
- auto unmap_page(T & allocator, virtual_page page) -> void
- {
- exception_handling::assert(translate_page(page).has_value(),
- "[Page Mapper] Attempted to unmap page, which has not been mapped previously");
-
- auto current_handle = active_handle;
-
- for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level)
- {
- auto const level_index = page.get_level_index(level);
- auto const next_handle = current_handle.next_table(level_index);
- // The next table method failed even tough the page has to be mapped already, because translate_page did not
- // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place.
- exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages");
- current_handle = next_handle.value();
- }
-
- unmap_page_table_entry(allocator, page, current_handle);
- kernel::cpu::tlb_flush(page.start_address());
- }
-
- private:
- /**
- * @brief Private constructor should only be used by create or get method, which ensures to create only ever one
- * instance.
- *
- * @param active_handle Handle to the underlying currently active level 4 page table.
- */
- active_page_table(page_table_handle active_handle);
-
- /**
- * @brief Deleted copy constructor.
- */
- active_page_table(active_page_table const &) = delete;
-
- /**
- * @brief Deleted copy assignment operator.
- */
- active_page_table & operator=(active_page_table const &) = delete;
-
- /**
- * @brief Unmaps specific page at the current internal handle level.
- *
- * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and
- * deallocate method.
- * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate
- * entries *when a new page table is required.
- * @param page Virtual page that is being unmapped.
- * @param handle Page Table handle we want to access the entry that should be cleared on.
- */
- template<allocator::FrameAllocator T>
- static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void
- {
- auto level_index = page.get_level_index(handle.get_level());
- auto & entry = handle[level_index];
- auto const frame = entry.calculate_pointed_to_frame();
- exception_handling::assert(frame.has_value(),
- "[Page Mapper] Attempted to unmap page, which has not been mapped previously");
- entry.set_unused();
- allocator.deallocate_frame(frame.value());
- }
-
- public:
- page_table_handle active_handle; ///< Underlying active level 4 page table
- };
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP
diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp
deleted file mode 100644
index 8d96740..0000000
--- a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP
-
-#include "arch/memory/allocator/physical_frame.hpp"
-#include "arch/memory/paging/active_page_table.hpp"
-#include "arch/memory/paging/temporary_page.hpp"
-
-namespace teachos::arch::memory::paging
-{
- /**
- * @brief By the CPU used level 4 page table.
- */
- struct inactive_page_table
- {
- /**
- * @brief Constructor.
- *
- * @param frame Frame that should be mapped as the level 4 page table.
- */
- inactive_page_table(allocator::physical_frame frame);
-
- /**
- * @brief Constructor.
- *
- * @param frame Frame that should be mapped as the level 4 page table.
- * @param active_page_table Actual active page table that should be unmapped so we can map a new level 4
- * page table.
- * @param temporary_page Temporary page that should be used to map the given frame as the new level 4 page
- * table.
- */
- inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table,
- temporary_page & temporary_page);
-
- allocator::physical_frame page_table_level_4_frame; ///< Temporary level 4 page table
- };
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP
diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp
deleted file mode 100644
index 81ac0cb..0000000
--- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP
-
-#include "arch/kernel/cpu/control_register.hpp"
-#include "arch/memory/paging/active_page_table.hpp"
-#include "arch/memory/paging/inactive_page_table.hpp"
-#include "arch/memory/paging/temporary_page.hpp"
-#include "arch/video/vga/text.hpp"
-
-#include <algorithm>
-#include <array>
-
-namespace teachos::arch::memory::paging
-{
- /**
- * @brief Kernel mapper that allows to remap the kernel elf sections in C++.
- *
- * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill.
- */
- template<allocator::FrameAllocator T>
- struct kernel_mapper
- {
- /**
- * @brief Constructor.
- *
- * @param allocator Allocator that should be used to allocate frames for the remapping process.
- * @param mem_info Information about elf kernel sections required for remapping process.
- */
- kernel_mapper(T & allocator, multiboot::memory_information const & mem_info)
- : allocator(allocator)
- , mem_info(mem_info)
- {
- // Nothing to do
- }
-
- /**
- * @brief Remap the kernel, meaning we map the entire kernel and all of it's elf sections with the correct flags
- * into memory and then replace the created mapping with the current one.
- *
- * @note We have to use a workaround with an
- * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because
- * remapping active kernel memory in the kernel wouldn't work.
- */
- auto remap_kernel() -> void
- {
- // Set Page Global Enable bit
- auto cr4 = kernel::cpu::read_control_register(kernel::cpu::control_register::CR4);
- kernel::cpu::write_control_register(kernel::cpu::control_register::CR4, cr4 | 0x80);
-
- temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator};
- decltype(auto) active_table = active_page_table::create_or_get();
- auto const frame = allocator.allocate_frame();
- exception_handling::assert(frame.has_value(),
- "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped");
- inactive_page_table new_table{frame.value(), active_table, temporary_page};
- remap_elf_kernel_sections(new_table, temporary_page, active_table);
- auto const old_table = switch_active_page_table(new_table);
- // Turn old level 4 page table, mapped by assembler code into stack guard page.
- // Only works if the identity mapped page tables by assembler are right above the stack.
- auto const old_level_4_page =
- virtual_page::containing_address(old_table.page_table_level_4_frame.start_address());
- active_table.unmap_page(allocator, old_level_4_page);
- }
-
- private:
- /**
- * @brief Remaps the kernel elf sections.
- *
- * This is done with switching the current level 4 page table recursive
- * mapping to any unmapped address in memory and then actually mapping the level 4 page table on that address.
- * Once the remapping process is done we can restore the original recursive mapping with the complete remapped
- * kernel.
- *
- * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before we
- * map the entries.
- *
- * @param inactive_table Level 4 page table we temporarily map the kernel into.
- * @param temporary_page Temporary page that should be used for the mapping process and then
- * unmapped once finished.
- * @param active_table Active level 4 page table that has its recursive mapping overwritten temporarily and then
- * restored once the process is finished.
- */
- auto remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page,
- active_page_table & active_table) -> void
- {
- auto const backup = allocator::physical_frame::containing_address(
- kernel::cpu::read_control_register(kernel::cpu::control_register::CR3));
- auto page_table_level4 = temporary_page.map_table_frame(backup, active_table);
-
- active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE);
- kernel::cpu::tlb_flush_all();
- map_elf_kernel_sections(active_table);
-
- page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE);
- kernel::cpu::tlb_flush_all();
- temporary_page.unmap_page(active_table);
- }
-
- /**
- * @brief Switches the current active table pointed to by the CR3 register with another page table that is currently
- * inactive.
- *
- * @param new_table Inactive page table that should now be made active and replace the current active one.
- * @return The previous active page table.
- */
- auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table
- {
- auto const backup = allocator::physical_frame::containing_address(
- kernel::cpu::read_control_register(kernel::cpu::control_register::CR3));
- auto const old_table = inactive_page_table{backup};
-
- auto const new_address = new_table.page_table_level_4_frame.start_address();
- kernel::cpu::write_control_register(kernel::cpu::control_register::CR3, new_address);
- return old_table;
- }
-
- /**
- * @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of
- * thoose frames gets the correct entry flags according to elf section flags.
- *
- * @param active_table Active level 4 page table that should be used to map the required elf sections into entries.
- * Has had its recursive mapping temporarily replaced and points to unmapped place in memory.
- */
- auto map_elf_kernel_sections(active_page_table & active_table) -> void
- {
- exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty");
- std::array<uint64_t, 6U> constexpr USER_SECTION_BASES = {
- 0x102000, // .boot_bss (Contains statically allocated variables)
- 0x209000, // .stl_text (Contains code for custom std implementations and standard library code)
- 0x218000, // .user_text (Contains the actual user code executed)
- 0x21F000, // .user_data (Contains static user variables)
-
- 0x20A000 // .text (Necessary, because symbols for all template standard library features are placed here if
- // they were first used in the Kernel Code Section)
- };
-
- for (auto const & section : mem_info.sections)
- {
- if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY))
- {
- continue;
- }
- exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U,
- "[Kernel Mapper] Section must be page aligned");
- auto const start_frame = allocator::physical_frame::containing_address(section.physical_address);
- // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this
- // section). But end frame would now point to the actual last frame and not one past the last frame, therefore
- // we increment by one to get one past the last frame of this section.
- auto const end_frame =
- ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1));
-
- allocator::frame_container::iterator const begin{start_frame};
- allocator::frame_container::iterator const end{end_frame};
- allocator::frame_container const frames{begin, end};
- entry entry{section.flags};
-
- if (std::ranges::find(USER_SECTION_BASES, section.physical_address) != USER_SECTION_BASES.end())
- {
- entry.set_user_accessible();
- }
-
- for (auto const & frame : frames)
- {
- active_table.identity_map(allocator, frame, entry.get_flags());
- }
- }
-
- auto const vga_buffer_frame =
- allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS);
- active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE);
- }
-
- T & allocator;
- multiboot::memory_information const &
- mem_info; ///< Information about elf kernel sections required for remapping process.
- };
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP
diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp
deleted file mode 100644
index 8147c5c..0000000
--- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP
-
-#include "arch/memory/allocator/physical_frame.hpp"
-#include "arch/memory/multiboot/elf_symbols_section.hpp"
-
-#include <bitset>
-#include <optional>
-
-namespace teachos::arch::memory::paging
-{
- /**
- * @brief Marks a specific entry in an actual page table.
- */
- struct entry
- {
- /**
- * @brief Possible set bits in our underlying std::bitset and the meaning when they are set.
- */
- enum bitset : uint64_t
- {
- PRESENT = 1UL << 0UL, ///< Page is in memory and therefore present.
- ///< is assumed to be READONLY and only that flag is shown in the objdump.
- WRITABLE = 1UL << 1UL, ///< It is possible to write to the page.
- USER_ACCESSIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code.
- WRITE_THROUGH_CACHING = 1UL << 3UL, ///< Write to the page go directly to memory instead of the cache.
- DISABLED_CACHING = 1UL << 4UL, ///< Page uses caching.
- ACCESSED = 1UL << 5UL, ///< Page is currently in use.
- DIRTY = 1UL << 6UL, ///< Page has been writen too.
- HUGE_PAGE = 1UL << 7UL, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table,
- ///< instead of 4 KiB). Has to be false for P1 and P4 page tables.
- GLOBAL = 1UL << 8UL, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register
- ///< has to be set)
- EXECUTING_CODE_FORBIDDEN =
- 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set)
- };
-
- /**
- * @brief Defaulted constructor.
- */
- entry() = default;
-
- /**
- * @brief Creates a new entry object from a 64bit address. Should follow the scheme where bit index 12 - 51 are the
- * actual address and the other bits are flags.
- *
- * @param flags Flags that will be passed to underlying std::bitset.
- */
- explicit entry(uint64_t flags);
-
- /**
- * @brief Creates a new entry converting the given elf section flags into the corresponding correct entry flags.
- *
- * @note Enables us to set the correct flags on a entry depending on which elf section it is contained in. For
- * example entries of .text sections should be executable and read only or entries of .data sections should be
- * writable but not executable.
- *
- * @param elf_flags Elf section flags we want to convert into entry flags.
- */
- explicit entry(multiboot::elf_section_flags elf_flags);
-
- /**
- * @brief Whether the current page is unused, meaning the underlying std::bitset is 0.
- *
- * @return Current page is in memory.
- */
- auto is_unused() const -> bool;
-
- /**
- * @brief Marks the page as unused, meaning the underlying std::bitset is set to 0.
- */
- auto set_unused() -> void;
-
- /**
- * @brief Marks the page as accessible in User mode, meaning the underlying std::bitset has the 2nd bit aditonally
- * set.
- */
- auto set_user_accessible() -> void;
-
- /**
- * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in
- * memory.
- *
- * @return Calculated physical frame entry is pointing too.
- */
- auto calculate_pointed_to_frame() const -> std::optional<allocator::physical_frame>;
-
- /**
- * @brief Copies the address and flags from the given physical frame into the underlying std::bitset
- *
- * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset.
- * @param additional_flags Entry flags which will be copied into our underlying std::bitset.
- */
- auto set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void;
-
- /**
- * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset.
- *
- * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng
- * std::bitset. Any additional bits that are set are not relevant.
- *
- * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set.
- * @return Whether the given flags are a subset or equivalent with the underlying std::bitset.
- */
- auto contains_flags(std::bitset<64U> other) const -> bool;
-
- /**
- * @brief Extracts only the flags from the underlying entry and ignores all bits that contain the physical address.
- *
- * @return Extracted entry flags, without the physical address.
- */
- auto get_flags() const -> std::bitset<64U>;
-
- private:
- std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be
- ///< freely used for additional flags by the operating system.
- };
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP
diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp
deleted file mode 100644
index b972337..0000000
--- a/arch/x86_64/include/arch/memory/paging/page_table.hpp
+++ /dev/null
@@ -1,157 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP
-
-#include "arch/exception_handling/assert.hpp"
-#include "arch/memory/allocator/concept.hpp"
-#include "arch/memory/paging/page_entry.hpp"
-
-namespace teachos::arch::memory::paging
-{
- std::size_t constexpr PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512.
-
- /**
- * @brief Forward delcaration of the page_table, because it should only be accessible over the handle.
- *
- * @note The actual methods or constructor are not defined meaning they are not callable from outside. Instead the
- * struct is only fully defined in the implementation (.cpp) file of the page table, and therefore the memthods are
- * only accesible in that file.
- */
- struct page_table;
-
- /**
- * @brief Handle that ensures accessing the page table is safe because it adds additional checks to the next_table
- * method and ensures it can only be called if the table level is not LEVEL1.
- */
- struct page_table_handle
- {
- /**
- * @brief Level of the page table.
- *
- * Level 1 will not be able to call next_table anymore, because it would result in
- * attempting to access memory that it should not.
- */
- enum level : uint8_t
- {
- LEVEL1,
- LEVEL2,
- LEVEL3,
- LEVEL4
- };
-
- /**
- * @brief Constructor.
- *
- * @param table Underlying page table the handle should point to.
- * @param table_level Level the underlying page table is on, used to ensure safety.
- */
- page_table_handle(page_table * table, level table_level);
-
- /**
- * @brief Set every entry of the page to unused.
- */
- auto zero_entries() -> void;
-
- /**
- * @brief Checks if all entries of this page are unused.
- */
- auto is_empty() const -> bool;
-
- /**
- * @brief Get the current table level.
- *
- * @return Current table level.
- */
- auto get_level() const -> level;
-
- /**
- * @brief Returns the next page table level from the given page table index. Meaning we
- * use an index into a Level 4 page table to get the according Level 3 page table.
- *
- * @note If this method is called with a Level 1 page table it will instead assert and halt execution, because there
- * is no furthere page table and mangeling up and returning the physical address would cause hard to debug issues.
- *
- * @param table_index Index of this page table in the page table one level lower.
- */
- auto next_table(std::size_t table_index) const -> std::optional<page_table_handle>;
-
- /**
- * @brief Call next_table and then checks if the table already exists, if it does not it will use the given
- * allocator to get the next free frame and set the entry to that instead.
- *
- * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate
- * entries when a new page table is required.
- * @param table_index Index of this page table in the page table one level lower.
- * @param flags A bitset of flags that configure the page table entry for this mapping.
- */
- template<allocator::FrameAllocator T>
- auto next_table_or_create(T & allocator, std::size_t table_index, std::bitset<64U> flags) -> page_table_handle
- {
- auto next_handle = next_table(table_index);
- // If the next table method failed then it means that the page level of the frame we want allocate has not yet
- // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done
- // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a
- // page table one level below.
- if (!next_handle.has_value())
- {
- auto const allocated_frame = allocator.allocate_frame();
- exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame");
- this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE);
- // There should now be an entry at the previously not existent index, therefore we can simply access it again.
- next_handle = next_table(table_index);
- exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table");
- next_handle.value().zero_entries();
- }
-
- // Check if the now created or previously created level 4, level 3 or level 2 page entry is used by user
- // accessible code. If it is that page entry needs to be user accesible as well.
- entry entry{flags.to_ulong()};
- if (entry.contains_flags(entry::USER_ACCESSIBLE))
- {
- this->operator[](table_index).set_user_accessible();
- }
- return next_handle.value();
- }
-
- /**
- * @brief Index operator overload to access specific mutable entry directy.
- *
- * @param index Index of the entry we want to access and only read.
- * @return Entry at the given table index.
- */
- auto operator[](std::size_t index) -> entry &;
-
- /**
- * @brief Index operator overload to access specific immutable entry directy.
- *
- * @param index Index of the entry we want to access and read or write.
- * @return Entry at the given table index.
- */
- auto operator[](std::size_t index) const -> entry const &;
-
- /**
- * @brief Pre decrement operator on the page table level enum, is defined so we can use it as a replacement
- * for an int index in a range based for loop.
- *
- * @note Will halt execution if called with page_table_handle::LEVEL1, because there is no level below. Has to be
- * defined as either a friend function or inline header method, because we define an operator of another type. In
- * this instance friend function was choosen, because the struct itself also requires the operator, but declaring
- * before the struct is not possible, because the enum is in the struct. This is inpossible because the struct
- * requires the operator declared before itself to work, and the operator requires the struct declared before itself
- * to work. Furthermore this allows the defintion of the method to be done in the cpp, avoiding includes in the
- * header file.
- *
- * @param value Value we want to decrement on
- * @return New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ...
- */
- friend auto operator--(level & value) -> level &;
-
- private:
- page_table * table; ///< Handle to underlying page table, can never be null (invariant ensured by
- ///< constructor)
- level table_level; ///< Level page table is currently on, depends on how often next_level was
- ///< called successfuly.
- };
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP
diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp
deleted file mode 100644
index d0d7781..0000000
--- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP
-
-#include "arch/memory/allocator/physical_frame.hpp"
-#include "arch/memory/allocator/tiny_frame_allocator.hpp"
-#include "arch/memory/paging/active_page_table.hpp"
-#include "arch/memory/paging/virtual_page.hpp"
-
-namespace teachos::arch::memory::paging
-{
- /**
- * @brief A temporary page used to remap the kernel.
- */
- struct temporary_page
- {
- /**
- * @brief Construct a new temporary page object.
- *
- * @tparam Type constraint of the allocator, being that is follows the given concept and contains an allocate and
- * deallocate method.
- * @param page Page to turn into temporary page.
- * @param allocator Frame allocator used to fill page.
- */
- template<allocator::FrameAllocator T>
- temporary_page(virtual_page page, T & allocator)
- : page{page}
- , allocator{allocator}
- {
- // Nothing to do
- }
-
- /**
- * @brief Unmap the current page.
- *
- * @param active_table The current active page table.
- */
- auto unmap_page(active_page_table & active_table) -> void;
-
- /**
- * @brief Map the temporary page to a frame.
- *
- * @param frame The frame to which the page is mapped.
- * @param active_table The current active page table.
- * @return level1 page table handle containing the mapped page.
- */
- auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle;
-
- private:
- /**
- * @brief Map the temporary page to a frame.
- *
- * @param frame The frame to which the page is mapped.
- * @param active_table The current active page table.
- * @return The virtual address of the page.
- */
- auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address;
-
- virtual_page page; ///< Underlying virtual page we want to temporarily map.
- allocator::tiny_frame_allocator allocator; ///< Allocator that should be used to map the temporary page.
- };
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP \ No newline at end of file
diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp
deleted file mode 100644
index a6c8c39..0000000
--- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP
-
-#include "arch/memory/allocator/physical_frame.hpp"
-#include "arch/memory/paging/page_table.hpp"
-
-#include <compare>
-#include <cstdint>
-#include <optional>
-
-namespace teachos::arch::memory::paging
-{
- using virtual_address = std::size_t;
-
- /**
- * @brief Virtual page entry contained in P1 page tables
- */
- struct virtual_page
- {
- /**
- * @brief Defaulted constructor.
- */
- constexpr virtual_page() = default;
-
- /**
- * @brief Constructor.
- *
- * @param page_number Index number of the current virtual page, used to distinguish it from other pages.
- */
- explicit constexpr virtual_page(std::size_t page_number)
- : page_number(page_number)
- {
- // Nothing to do
- }
-
- /**
- * @brief Returns the virtual page the given address is contained in.
- *
- * @param address Virtual address we want to get the corresponding virtual page for.
- * @return Frame the given address is contained in.
- */
- auto static containing_address(virtual_address address) -> virtual_page;
-
- /**
- * @brief Evaluates the start address of the virtual page.
- *
- * @return Start address of the virtual page.
- */
- auto start_address() const -> virtual_address;
-
- /**
- * @brief Calculates the index into the page table with the given level, which leads to this virtual page.
- *
- * @param level Level of the page table we want to calculate the index for.
- * @return Index into the page table with the given level.
- */
- auto get_level_index(page_table_handle::level level) const -> size_t;
-
- /**
- * @brief Post increment operator. Returns a copy of the value.
- *
- * @return Copy of the incremented underlying page number.
- */
- auto operator++(int) -> virtual_page;
-
- /**
- * @brief Pre increment operator. Returns a reference to the changed value.
- *
- * @return Reference to the incremented underlying page number.
- */
- auto operator++() -> virtual_page &;
-
- /**
- * @brief Defaulted equals operator.
- */
- auto operator==(const virtual_page & other) const -> bool = default;
-
- /**
- * @brief Defaulted three-way comparsion operator.
- */
- auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default;
-
- std::size_t page_number =
- {}; ///< Index number of the current virtual page, used to distinguish it from other pages.
- };
-
- using page_container = stl::container<stl::forward_value_iterator<virtual_page>>;
-
-} // namespace teachos::arch::memory::paging
-
-#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP
diff --git a/arch/x86_64/include/arch/stl/container.hpp b/arch/x86_64/include/arch/stl/container.hpp
deleted file mode 100644
index 4ea08c7..0000000
--- a/arch/x86_64/include/arch/stl/container.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_CONTAINER_HPP
-#define TEACHOS_ARCH_X86_64_STL_CONTAINER_HPP
-
-#include <iterator>
-
-namespace teachos::arch::stl
-{
- /**
- * @brief Minimal iterator concept required for usage in container
- */
- template<typename T>
- concept Iterator = std::forward_iterator<T>;
-
- /**
- * @brief Read-only container for given template type, that allow to easily use this container instance in C++20
- * ranges calls.
- *
- * @tparam T Iterator the container uses to signal the start and end of it's data, has to atleast be a simple forward
- * iterator.
- */
- template<Iterator T>
- struct container
- {
- using iterator = T; ///< Iterators used by this container.
- using size_type = std::size_t; ///< Maximum size of this container.
-
- /**
- * @brief Defaulted constructor.
- */
- container() = default;
-
- /**
- * @brief Constructor.
- *
- * @param begin Iterator containing non-owning pointer to the first element of all memory areas.
- * @param end Iterator pointing to one past the last element of all memory areas.
- */
- container(iterator begin, iterator end)
- : begin_itr(begin)
- , end_itr(end)
- {
- // Nothing to do
- }
-
- /**
- * @brief Returns the iterator pointing to the first element of the memory area.
- * Allows using this class in the for each loop, because it follows the InputIterator template scheme.
- *
- * @return Iterator pointing to first element of the memory area.
- */
- [[gnu::section(".stl_text")]]
- auto begin() const -> iterator
- {
- return begin_itr;
- }
-
- /**
- * @brief Returns the iterator pointing to one past the last element of the memory area.
- * Allows using this class in the for each loop, because it follows the InputIterator template scheme.
- *
- * @return Iterator pointing to one past the last element of the memory area.
- */
- [[gnu::section(".stl_text")]]
- auto end() const -> iterator
- {
- return end_itr;
- }
-
- /**
- * @brief Calculates the size of this container, simply subtracts the iterator pointing to the first element by the
- * last.
- *
- * @return Actual size of this container.
- */
- [[gnu::section(".stl_text")]]
- auto size() const -> size_type
- {
- return std::distance(begin(), end());
- }
-
- /**
- * @brief Calcualtes the size and returns true if the size is 0 and the container therefore emtpy.
- *
- * @return Whether the container is empty, size being 0 or not
- */
- [[gnu::section(".stl_text")]]
- auto empty() const -> bool
- {
- return size() == 0;
- }
-
- private:
- iterator begin_itr = {}; ///< Pointer to the first element of the given template type.
- iterator end_itr = {}; ///< Pointer to one pas the last element of the given template type.
- };
-
-} // namespace teachos::arch::stl
-
-#endif // TEACHOS_ARCH_X86_64_STL_CONTAINER_HPP
diff --git a/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp b/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp
deleted file mode 100644
index f2dfb2b..0000000
--- a/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_CONTIGUOUS_POINTER_ITERATOR_HPP
-#define TEACHOS_ARCH_X86_64_STL_CONTIGUOUS_POINTER_ITERATOR_HPP
-
-#include <iterator>
-
-namespace teachos::arch::stl
-{
- /**
- * @brief Generic contiguous iterator for given template type. Allows to easily use this iterator instance in
- * algorithm calls.
- *
- * @note Allows any value that is contained in an array in memory, which is a block of contiguous memory. This is the
- * case because we assume we can simply increment or decrement the pointer address to get the next valid instance of
- * the given value type.
- *
- * @tparam T Value the iterator points too.
- */
- template<typename T>
- struct contiguous_pointer_iterator
- {
- using iterator_category = std::contiguous_iterator_tag; ///< Iterator category of this type.
- using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another.
- using value_type = T; ///< Underlying value pointed to by this iterator.
- using reference_type = value_type &; ///< Reference to value returned by dereference * operation.
- using pointer_type = value_type *; ///< Pointer to value returned by arrow -> operation.
-
- /**
- * @brief Defaulted constructor.
- */
- contiguous_pointer_iterator() = default;
-
- /**
- * @brief Constructor.
- *
- * @param p Underlying address the iterator should point too.
- */
- explicit contiguous_pointer_iterator(value_type * p)
- : ptr(p)
- {
- // Nothing to do
- }
-
- /**
- * @brief Dereferences the initally given pointer to its value.
- *
- * @return Reference to the value.
- */
- [[gnu::section(".stl_text")]]
- auto operator*() const -> reference_type
- {
- return *ptr;
- }
-
- /**
- * @brief Get underlying value, which is the intially passed pointer.
- *
- * @return Pointer to the underlying value passed intially.
- */
- [[gnu::section(".stl_text")]]
- auto operator->() const -> pointer_type
- {
- return ptr;
- }
-
- /**
- * @brief Pre decrement operator. Returns a reference to the changed address.
- *
- * @return Reference to the decremented underlying address.
- */
- [[gnu::section(".stl_text")]]
- auto operator--() -> contiguous_pointer_iterator &
- {
- contiguous_pointer_iterator const old_value = *this;
- ++ptr;
- return old_value;
- }
-
- /**
- * @brief Pre increment operator. Returns a reference to the changed address.
- *
- * @return Reference to the incremented underlying address.
- */
- [[gnu::section(".stl_text")]]
- auto operator++() -> contiguous_pointer_iterator &
- {
- ++ptr;
- return *this;
- }
-
- /**
- * @brief Post decrement operator. Returns a copy of the address.
- *
- * @return Copy of the decremented underlying address.
- */
- [[gnu::section(".stl_text")]]
- auto operator--(int) -> contiguous_pointer_iterator
- {
- auto const old_value = *this;
- --ptr;
- return old_value;
- }
-
- /**
- * @brief Post increment operator. Returns a copy of the address.
- *
- * @return Copy of the incremented underlying address.
- */
- [[gnu::section(".stl_text")]]
- auto operator++(int) -> contiguous_pointer_iterator
- {
- auto const old_value = *this;
- ++ptr;
- return old_value;
- }
-
- /**
- * @brief Addition assignment operator. Returns a reference to the changed address.
- *
- * @param value Value we want to add to the underlying address.
- * @return Reference to the changed underlying address.
- */
- [[gnu::section(".stl_text")]]
- auto operator+=(difference_type value) -> contiguous_pointer_iterator &
- {
- ptr += value;
- return *this;
- }
-
- /**
- * @brief Subtraction assignment operator. Returns a reference to the changed address.
- *
- * @param value Value we want to subtract from the underlying address.
- * @return Reference to the changed underlying address.
- */
- [[gnu::section(".stl_text")]]
- auto operator-=(difference_type value) -> contiguous_pointer_iterator &
- {
- ptr -= value;
- return *this;
- }
-
- /**
- * @brief Addition operator. Returns the changed address.
- *
- * @param value Value we want to add to a copy of the underlying address.
- * @return Copy of underlying address incremented by the given value.
- */
- [[gnu::section(".stl_text")]]
- auto operator+(difference_type value) const -> contiguous_pointer_iterator
- {
- return contiguous_pointer_iterator{ptr + value};
- }
-
- /**
- * @brief Subtraction operator. Returns the changed address.
- *
- * @param value Value we want to subtrcat from a copy of the underlying address.
- * @return Copy of underlying address decremented by the given value.
- */
- [[gnu::section(".stl_text")]]
- auto operator-(difference_type value) const -> contiguous_pointer_iterator
- {
- return contiguous_pointer_iterator{ptr - value};
- }
-
- /**
- * @brief Subtraction operator. Returns the size difference between two iterators.
- *
- * @param other Other iterator we want to substract the underlying address with ours.
- * @return Size difference between the underlying address of this instance and the given iterator.
- */
- [[gnu::section(".stl_text")]]
- auto operator-(const contiguous_pointer_iterator & other) const -> difference_type
- {
- return ptr - other.ptr;
- }
-
- /**
- * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the
- * dereferenced underlying pointer incremented by the given index.
- *
- * @param index Index we want to access and get the value from.
- * @return Reference to the value at the given index.
- */
- [[gnu::section(".stl_text")]]
- auto operator[](difference_type index) const -> value_type &
- {
- return *(ptr + index);
- }
-
- /**
- * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators.
- *
- * @param other Other iterator to compare to.
- * @return Whether both iterators point to the same underlying address in memory.
- */
- [[gnu::section(".stl_text")]]
- auto operator==(contiguous_pointer_iterator const & other) const -> bool = default;
-
- /**
- * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators.
- *
- * @param other Other iterator to compare to.
- * @return Whether the given iterator is smaller or larger than this iterator.
- */
- [[gnu::section(".stl_text")]]
- auto operator<=>(contiguous_pointer_iterator const & other) const -> std::strong_ordering = default;
-
- private:
- pointer_type ptr =
- {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement.
- };
-
-} // namespace teachos::arch::stl
-
-#endif // TEACHOS_ARCH_X86_64_STL_CONTIGUOUS_POINTER_ITERATOR_HPP
diff --git a/arch/x86_64/include/arch/stl/forward_value_iterator.hpp b/arch/x86_64/include/arch/stl/forward_value_iterator.hpp
deleted file mode 100644
index be3d8e6..0000000
--- a/arch/x86_64/include/arch/stl/forward_value_iterator.hpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_FORWARD_VALUE_ITERATOR_HPP
-#define TEACHOS_ARCH_X86_64_STL_FORWARD_VALUE_ITERATOR_HPP
-
-#include <iterator>
-
-namespace teachos::arch::stl
-{
- /**
- * @brief Concept for a type to have a post and prefix increment operator, that returns the correct type.
- */
- template<typename T>
- concept Incrementable = requires(T t) {
- { ++t } -> std::same_as<T &>;
- { t++ } -> std::same_as<T>;
- };
-
- /**
- * @brief Iterable concept for the forward value iterator, meaning the type itself is incrementable and comparable.
- */
- template<typename T>
- concept Iterable = std::regular<T> && Incrementable<T>;
-
- /**
- * @brief Generic forward iterator for given template type. Allows to easily use this iterator
- * instance in algorithm calls.
- *
- * @note Allows any value that itself can be incremented until we have reached the end, does not interact with the
- * address of the value in any way.
- *
- * @tparam T Value the iterator contains.
- */
- template<Iterable T>
- struct forward_value_iterator
- {
- using iterator_category = std::forward_iterator_tag; ///< Iterator category of this type.
- using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another.
- using value_type = T; ///< Underlying value contained by this iterator.
- using const_reference_type =
- value_type const &; ///< Constant reference to value returned by dereference * operation.
- using const_pointer_type = value_type const *; ///< Constant pointer to value returned by arrow -> operation.
-
- /**
- * @brief Defaulted constructor.
- */
- forward_value_iterator() = default;
-
- /**
- * @brief Constructor.
- *
- * @param value Underlying value the iterator contains.
- */
- explicit forward_value_iterator(value_type value)
- : value(value)
- {
- // Nothing to do
- }
-
- /**
- * @brief Returns the initally given value.
- *
- * @return Reference to the value.
- */
- [[gnu::section(".stl_text")]]
- auto operator*() const -> const_reference_type
- {
- return value;
- }
-
- /**
- * @brief Gets pointer to the underlying value passed intially.
- *
- * @return Pointer to the underlying value passed intially.
- */
- [[gnu::section(".stl_text")]]
- auto operator->() const -> const_pointer_type
- {
- return &value;
- }
-
- /**
- * @brief Pre increment operator. Returns a reference to the changed value.
- *
- * @return Reference to the incremented underlying value.
- */
- [[gnu::section(".stl_text")]]
- auto operator++() -> forward_value_iterator &
- {
- ++value;
- return *this;
- }
-
- /**
- * @brief Post increment operator. Returns a copy of the value.
- *
- * @return Copy of the incremented underlying value.
- */
- [[gnu::section(".stl_text")]]
- auto operator++(int) -> forward_value_iterator
- {
- auto const old_value = *this;
- ++value;
- return old_value;
- }
-
- /**
- * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators.
- *
- * @param other Other iterator to compare to.
- * @return Whether both iterators point to the same underlying address in memory.
- */
- [[gnu::section(".stl_text")]]
- auto operator==(forward_value_iterator const & other) const -> bool = default;
-
- private:
- value_type value =
- {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement.
- };
-
-} // namespace teachos::arch::stl
-
-#endif // TEACHOS_ARCH_X86_64_STL_FORWARD_VALUE_ITERATOR_HPP
diff --git a/arch/x86_64/include/arch/video/vga/io.hpp b/arch/x86_64/include/arch/video/vga/io.hpp
deleted file mode 100644
index c399fad..0000000
--- a/arch/x86_64/include/arch/video/vga/io.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_VIDEO_VGA_IO_HPP
-#define TEACHOS_ARCH_X86_64_VIDEO_VGA_IO_HPP
-
-#include "arch/io/port_io.hpp"
-
-#include <cstddef>
-
-namespace teachos::arch::video::vga
-{
- namespace crtc
- {
- /**
- * @brief The address port of the CRT Controller.
- */
- using address_port = arch::io::port<0x3d4, 1>;
-
- /**
- * @brief The data port of the CRT Controller.
- */
- using data_port = arch::io::port<0x3d5, 1>;
-
- namespace registers
- {
- /**
- * @brief The address of the Cursor Start register of the CRTC.
- */
- [[maybe_unused]] auto constexpr cursor_start = std::byte{0x0a};
-
- /**
- * @brief The address of the Cursor End register of the CRTC.
- */
- [[maybe_unused]] auto constexpr curser_end = std::byte{0x0b};
- } // namespace registers
-
- }; // namespace crtc
-
-} // namespace teachos::arch::video::vga
-
-#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_IO_HPP
diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp
deleted file mode 100644
index cfbf98f..0000000
--- a/arch/x86_64/include/arch/video/vga/text.hpp
+++ /dev/null
@@ -1,169 +0,0 @@
-#ifndef TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP
-#define TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP
-
-#include <cstdint>
-#include <string_view>
-#include <type_traits>
-
-namespace teachos::arch::video::vga::text
-{
- auto constexpr DEFAULT_VGA_TEXT_BUFFER_ADDRESS = 0xB8000;
-
- /**
- * @brief The colors available in the standard VGA text mode.
- */
- enum struct color : std::uint8_t
- {
- black, ///< Equivalent to HTML color \#000000.
- blue, ///< Equivalent to HTML color \#0000AA.
- green, ///< Equivalent to HTML color \#00AA00.
- cyan, ///< Equivalent to HTML color \#00AAAA.
- red, ///< Equivalent to HTML color \#AA0000.
- purple, ///< Equivalent to HTML color \#AA00AA.
- brown, ///< Equivalent to HTML color \#AA5500.
- gray, ///< Equivalent to HTML color \#AAAAAA.
- };
-
- /**
- * @brief The foreground color modification flag.
- */
- enum struct foreground_flag : bool
- {
- none, ///< Apply no flag e.g., keep color as is.
- intense, ///< Make the color more intense (usually brighter).
- };
-
- /**
- * @brief The background color modification flag.
- */
- enum struct background_flag : bool
- {
- none, ///< Apply no flag e.g., keep color as is.
- blink_or_bright, ///< Make the cell blink or more intense, dependent on the VGA configuration.
- };
-
- /**
- * @brief The VGA text mode attribute.
- *
- * @note In the text mode of VGA, every code point being presented is followed by an attribute description. This
- * allows for the modification of how the relevant "cell" is presented.
- *
- * @see vga::text::foreground_flag
- * @see vga::text::background_flag
- */
- struct attribute
- {
- color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point.
- enum foreground_flag foreground_flag : 1; ///< The foreground color modification flag of the cell.
- color bacground_color : 3; ///< The background color of the cell.
- enum background_flag background_flag : 1; ///< The background color modification flag of the cell.
- };
-
- static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte.");
-
- /**
- * @brief Commonly used VGA text mode attributes.
- */
- namespace common_attributes
- {
- /**
- * @brief Make the affected cell display with a gray foreground and black background.
- */
- [[maybe_unused]] auto constexpr gray_on_black =
- attribute{color::gray, foreground_flag::none, color::black, background_flag::none};
-
- /**
- * @brief Make the affected cell display with a green foreground and black background.
- */
- [[maybe_unused]] auto constexpr green_on_black =
- attribute{color::green, foreground_flag::none, color::black, background_flag::none};
-
- /**
- * @brief Make the affected cell display with a white (gray + intense) foreground and red background.
- */
- [[maybe_unused]] auto constexpr white_on_red =
- attribute{color::gray, foreground_flag::intense, color::red, background_flag::none};
- } // namespace common_attributes
-
- /**
- * @brief Clear the VGA text mode buffer.
- *
- * @note This function also resets the text mode buffer pointer.
- *
- * @param attribute The attribute to "clear" the screen with.
- */
- auto clear(attribute attribute = common_attributes::gray_on_black) -> void;
-
- /**
- * @brief Enable or disable the VGA text mode cursor.
- *
- * @param enabled Whether or not to enable the cursors.
- */
- auto cursor(bool enabled) -> void;
-
- /**
- * @brief Move the cursor to a new line, scrolling the buffer if necessary.
- */
- auto newline() -> void;
-
- /**
- * @brief Write a string of code points to the VGA text buffer.
- *
- * @note This function also updates the text mode buffer pointer.
- *
- * @param code_points A string of (8-bit) code points to write to the VGA text mode buffer.
- * @param attribute The attribute to apply to the written sequence of code points.
- * @see vga::text::attribute
- */
- auto write(std::string_view code_points, attribute attribute) -> void;
-
- /**
- * @brief Write a single character to the VGA text buffer.
- *
- * @note This function also updates the text mode buffer pointer.
- *
- * @param code_point A code point to write to the VGA text mode buffer.
- * @param attribute The attribute to apply to the written sequence of code points.
- * @see vga::text::attribute
- */
- auto write_char(char code_point, attribute attribute) -> void;
-
- template<typename T>
- concept Integral = std::is_integral_v<T>;
-
- /**
- * @brief Write a integral value to the VGA text buffer.
- *
- * @note This function also updates the text mode buffer pointer.
- *
- * @param value A integral value to write to the VGA text mode buffer.
- * @param attribute The attribute to apply to the written sequence of code points.
- * @see vga::text::attribute
- */
- template<Integral T>
- auto write_number(T value, attribute attribute) -> void
- {
- T current_value = value;
- T divisor = 1;
-
- while (current_value > 9)
- {
- divisor *= 10;
- current_value = current_value / 10;
- }
-
- current_value = value;
- while (divisor > 0)
- {
- uint8_t quotient = current_value / divisor;
- char ascii_digit = quotient + '0';
-
- write_char(ascii_digit, attribute);
- current_value %= divisor;
- divisor /= 10;
- }
- }
-
-} // namespace teachos::arch::video::vga::text
-
-#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp
new file mode 100644
index 0000000..2c44659
--- /dev/null
+++ b/arch/x86_64/include/x86_64/boot/boot.hpp
@@ -0,0 +1,70 @@
+#ifndef TEACHOS_X86_64_BOOT_BOOT_H
+#define TEACHOS_X86_64_BOOT_BOOT_H
+
+#ifdef __ASSEMBLER__
+/* clang-format off */
+/**
+ * @brief The number of huge pages to map during bootstrap.
+ */
+#define HUGE_PAGES_TO_MAP (16)
+
+/**
+ * @brief The magic value to be set in eax by the multiboot 2 loader.
+ */
+#define MULTIBOOT2_MAGIC (0x36d76289)
+
+/**
+ * @brief The "A" bit in a GDT entry.
+ */
+#define GDT_ACCESSED (1 << 40)
+
+/**
+ * @brief The "R/W" bit in a GDT entry
+ */
+#define GDT_READ_WRITE (1 << 41)
+
+/**
+ * @brief The "E" bit in a GDT entry.
+ */
+#define GDT_EXECUTABLE (1 << 43)
+
+/**
+ * @brief The "S" bit in a GDT entry.
+ */
+#define GDT_DESCRIPTOR_TYPE (1 << 44)
+
+/**
+ * @brief The "P" bit in a GDT entry.
+ */
+#define GDT_PRESENT (1 << 47)
+
+/**
+ * @brief The "L" bit in a GDT entry.
+ */
+#define GDT_LONG_MODE (1 << 53)
+/* clang-format on */
+#else
+
+#include "kapi/boot.hpp" // IWYU pragma: export
+
+#include <multiboot2/information.hpp>
+
+#include <cstddef>
+
+namespace teachos::boot
+{
+
+ struct information
+ {
+ //! A pointer to the loader provided Multiboot2 Information structure.
+ multiboot2::information_view const * mbi;
+
+ //! The index of the next character to be written in the VGA text buffer after handoff.
+ std::size_t vga_buffer_index;
+ };
+
+} // namespace teachos::boot
+
+#endif
+
+#endif
diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp
new file mode 100644
index 0000000..b073863
--- /dev/null
+++ b/arch/x86_64/include/x86_64/boot/ld.hpp
@@ -0,0 +1,61 @@
+//! @file
+//! The interface to linker script defined symbols.
+//!
+//! This header provides declarations for symbols that are defined in the linker script itself. The symbols declared
+//! here provide important information, for example the start and end of the kernel image in virtual and physical
+//! memory.
+//!
+//! Any variables defined in this file must not be read themselves, but rather their address shall be taken, yielding a
+//! pointer to the memory location the represent.
+//!
+//! @note The symbols declared in this header are declared using C-language linkage in order to suppress name mangling.
+//!
+//! @see arch/x86_64/scripts/kernel.ld
+
+#ifndef TEACHOS_X86_64_BOOT_LD_HPP
+#define TEACHOS_X86_64_BOOT_LD_HPP
+
+#include <cstddef>
+
+namespace teachos::boot::x86_64
+{
+
+ extern "C"
+ {
+ //! The beginning of the kernel image in physical memory
+ //!
+ //! This symbol marks the start of the kernel image in physical memory.
+ //!
+ //! @see _end_physical
+ extern std::byte _start_physical;
+
+ //! The first byte after the loaded kernel image.
+ //!
+ //! This symbol marks the end of the kernel image in physical memory.
+ //!
+ //! @see _start_physical
+ extern std::byte _end_physical;
+
+ //! The first byte of the loaded kernel image in the virtual address space.
+ //!
+ //! This symbol and marks the start of the kernel image in virtual memory.
+ //!
+ //! @see _end_virtual
+ extern std::byte _start_virtual;
+
+ //! The first byte after the loaded kernel image in the virtual address space.
+ //!
+ //! This symbol marks the end of the kernel image in virtual memory.
+ //!
+ //! @see _start_virtual
+ extern std::byte _end_virtual;
+
+ //! The first byte of the kernel's virtual address space.
+ //!
+ //! This symbol marks beginning of the kernel virtual address space.
+ extern std::byte TEACHOS_VMA;
+ }
+
+} // namespace teachos::boot::x86_64
+
+#endif
diff --git a/arch/x86_64/include/x86_64/cpu/control_register.hpp b/arch/x86_64/include/x86_64/cpu/control_register.hpp
new file mode 100644
index 0000000..35ffcae
--- /dev/null
+++ b/arch/x86_64/include/x86_64/cpu/control_register.hpp
@@ -0,0 +1,244 @@
+#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP
+#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP
+
+// IWYU pragma: private, include "x86_64/cpu/registers.hpp"
+
+#include "kapi/memory/address.hpp"
+
+#include <kstd/ext/bitfield_enum>
+
+#include <cstdint>
+#include <string_view>
+#include <type_traits>
+
+namespace teachos::cpu::x86_64
+{
+ namespace impl
+ {
+ //! The assembler templates used to access (r/w) CR0;
+ constexpr auto static cr0_asm = std::pair<std::string_view, std::string_view>{"mov %%cr0, %0", "mov %0, %%cr0"};
+
+ //! The assembler templates used to access (r/w) CR2;
+ constexpr auto static cr2_asm = std::pair<std::string_view, std::string_view>{"mov %%cr2, %0", "mov %0, %%cr2"};
+
+ //! The assembler templates used to access (r/w) CR3;
+ constexpr auto static cr3_asm = std::pair<std::string_view, std::string_view>{"mov %%cr3, %0", "mov %0, %%cr3"};
+ } // namespace impl
+
+ //! The flags that can be set on CR0 configuration register.
+ enum struct cr0_flags : uint64_t
+ {
+ //! Enable protected mode.
+ protection_enable = 1uz << 0,
+ //! Enable wait-monitoring of the coprocessor after task switching.
+ monitor_coprocessor = 1uz << 1,
+ //! Emulate floating point coprocessor.
+ emulation = 1uz << 2,
+ //! Marks that a task switch has occurred.
+ task_switched = 1uz << 3,
+ //! Marks Intel 387 DX math coprocessor as available
+ extension_type = 1uz << 4,
+ //! Numeric error handling mode.
+ numeric_error = 1uz << 5,
+ //! Disable writing to read-only marked memory.
+ write_protect = 1uz << 16,
+ //! Enable Ring-3 alignment checks
+ alignment_check = 1uz << 18,
+ //! Disable write through
+ not_write_through = 1uz << 29,
+ //! Disable caching of memory accesses
+ cache_disable = 1uz << 30,
+ //! Enable paging
+ paging = 1uz << 31
+ };
+
+ enum struct cr3_flags : std::uint64_t
+ {
+ page_level_write_through = 1uz << 0,
+ page_level_cache_disable = 1uz << 1,
+ };
+} // namespace teachos::cpu::x86_64
+
+namespace kstd::ext
+{
+ template<>
+ struct is_bitfield_enum<teachos::cpu::x86_64::cr0_flags> : std::true_type
+ {
+ };
+
+ template<>
+ struct is_bitfield_enum<teachos::cpu::x86_64::cr3_flags> : std::true_type
+ {
+ };
+} // namespace kstd::ext
+
+namespace teachos::cpu::x86_64
+{
+ //! A mixin for flag-oriented control registers.
+ //!
+ //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A
+ //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts.
+ //!
+ //! @tparam Derived The class deriving from this mixin.
+ //! @tparam ValueType The value type of the class deriving from this mixin.
+ template<typename Derived, typename ValueType, typename = void>
+ struct control_register_with_flags
+ {
+ };
+
+ //! @copydoc control_register_with_flags
+ //!
+ //! @note This specialization provides the implementation for the case in which the value type of the control register
+ //! is an enum.
+ template<typename Derived, typename ValueType>
+ struct control_register_with_flags<Derived, ValueType, std::enable_if_t<kstd::ext::bitfield_enum<ValueType>>>
+ {
+ //! The type of the flags used by this control register
+ using flags = ValueType;
+
+ //! Set one or more flags in this control register.
+ //!
+ //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to
+ //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function
+ //! will perform no additional checks, and may, by extension, crash the system.
+ //!
+ //! @param value One or a combination of flags to be set in the control register.
+ auto static set(ValueType value) -> void
+ {
+ auto current = Derived::read();
+ current |= value;
+ Derived::write(current);
+ }
+
+ //! Clear one or more flags in this control register.
+ //!
+ //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to
+ //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function
+ //! will perform no additional checks, and may, by extension, crash the system.
+ //!
+ //! @param value One or a combination of flags to be cleared in the control register.
+ auto static clear(ValueType value) -> void
+ {
+ auto current = Derived::read();
+ current &= ~value;
+ Derived::write(current);
+ }
+ };
+
+ //! A CPU control register.
+ //!
+ //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU
+ //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU
+ //! in an invalid/undefined state.
+ template<typename ValueType, auto AssemblerTemplates>
+ struct control_register : control_register_with_flags<control_register<ValueType, AssemblerTemplates>, ValueType>
+ {
+ //! Read the current value of the control register.
+ //!
+ //! @return The currently set value of the control register.
+ [[nodiscard]] auto static read() -> ValueType
+ {
+ auto value = ValueType{};
+ asm volatile((AssemblerTemplates->first) : "=r"(value));
+ return value;
+ }
+
+ //! Write a new value to the control register.
+ //!
+ //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to
+ //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function
+ //! will perform no additional checks, and may, by extension, crash the system.
+ //!
+ //! @param value The new value to write to the control register.
+ auto static write(ValueType value) -> void
+ {
+ asm volatile((AssemblerTemplates->second) : : "r"(value));
+ }
+ };
+
+ //! The value type of the CR3 control register.
+ //!
+ //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the
+ //! page aligned physical address of the root page map, as well as the root paging configuration flags.
+ struct cr3_value
+ {
+ //! Contstruct a 0-value CR3 value.
+ constexpr cr3_value() = default;
+
+ //! Construct a CR3 value using the given root page map address and flags.
+ //!
+ //! @param address The physical address of the root page map
+ //! @param flags The root configuration flags of the paging system.
+ constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast<cr3_flags>(0))
+ : m_flags{static_cast<std::uint64_t>(flags)}
+ , m_address{static_cast<std::uint64_t>(address.raw())}
+ {}
+
+ //! Extract the physical address of the root page map from this value.
+ //!
+ //! @return The physical address of the root page map.
+ [[nodiscard]] constexpr auto address() const -> memory::physical_address
+ {
+ return memory::physical_address{m_address};
+ }
+
+ //! Encode the page aligned physical address of the root page map into this value.
+ //!
+ //! @param address The page aligned physical address of the root page map.
+ constexpr auto address(memory::physical_address address) -> void
+ {
+ m_address = static_cast<std::uint64_t>(address.raw());
+ }
+
+ //! Extract the root paging configuration flags from this value.
+ //!
+ //! @return The root paging configuration flags.
+ [[nodiscard]] constexpr auto flags() const -> cr3_flags
+ {
+ return static_cast<cr3_flags>(m_flags);
+ }
+
+ //! Encode the root paging configuration flags into this value.
+ //!
+ //! @param flags The root paging configuration flags.
+ constexpr auto flags(cr3_flags flags) -> void
+ {
+ m_flags = static_cast<std::uint64_t>(flags);
+ }
+
+ //! Add the given flags to the current set of encoded root configuration flags of this value.
+ //!
+ //! @param flags The root configuration flags to add.
+ //! @return A reference to this value.
+ constexpr auto operator|=(cr3_flags flags) -> cr3_value &
+ {
+ m_flags |= static_cast<std::uint64_t>(flags);
+ return *this;
+ }
+
+ //! Mask the root configuration flags of this value.
+ //!
+ //! @param mask The mask to apply to the root configuration flags.
+ //! @return A reference to this value.
+ constexpr auto operator&=(cr3_flags mask) -> cr3_value &
+ {
+ m_flags &= static_cast<std::uint64_t>(mask);
+ return *this;
+ }
+
+ private:
+ //! Reserved bits.
+ std::uint64_t : 3;
+ //! The root paging configuration flags.
+ std::uint64_t m_flags : 2 {};
+ //! Reserved bits.
+ std::uint64_t : 7;
+ //! The page aligned physical address of the root page map.
+ std::uint64_t m_address : 52 {};
+ };
+
+ static_assert(sizeof(cr3_value) == sizeof(std::uint64_t));
+
+} // namespace teachos::cpu::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp b/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp
new file mode 100644
index 0000000..857b444
--- /dev/null
+++ b/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp
@@ -0,0 +1,148 @@
+#ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP
+#define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP
+
+// IWYU pragma: private, include "x86_64/cpu/registers.hpp"
+
+#include <kstd/ext/bitfield_enum>
+
+#include <bit>
+#include <cstdint>
+#include <type_traits>
+
+namespace teachos::cpu::x86_64
+{
+
+ //! The flags of the IA32_EFER (Extended Features Enable Register) MSR.
+ enum struct ia32_efer_flags : std::uint64_t
+ {
+ //! Enable the syscall and sysret instructions.
+ syscall_enable = 1uz << 0,
+ //! Enable IA-32e mode operation.
+ ia32e_mode_enable = 1uz << 8,
+ //! Indicates IA-32e mode is active (read-only)
+ ia32e_mode_active = 1uz << 10,
+ //! Enable the use of the NX page table bit.
+ execute_disable_bit_enable = 1uz << 11,
+ };
+
+} // namespace teachos::cpu::x86_64
+
+namespace kstd::ext
+{
+
+ template<>
+ struct is_bitfield_enum<teachos::cpu::x86_64::ia32_efer_flags> : std::true_type
+ {
+ };
+
+} // namespace kstd::ext
+
+namespace teachos::cpu::x86_64
+{
+ //! The MSR number for the IA32_EFER MSR
+ constexpr auto ia32_efer_number = 0xC000'0080u;
+
+ //! A mixin for flag-oriented model specific registers.
+ //!
+ //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific
+ //! register is flag-oriented, if it comprises a single field of bitfield.
+ //!
+ //! @tparam Derived The class deriving from this mixin.
+ //! @tparam ValueType The value type of the class deriving from this mixin.
+ template<typename Derived, typename ValueType, typename = void>
+ struct model_specific_register_with_flags
+ {
+ };
+
+ //! @copydoc model_specific_register_with_flags
+ //!
+ //! @note This specialization provides the implementation for the case in which the value type of the model specific
+ //! register is a bitfield enum.
+ template<typename Derived, typename ValueType>
+ struct model_specific_register_with_flags<Derived, ValueType, std::enable_if_t<kstd::ext::bitfield_enum<ValueType>>>
+ {
+ //! The of the flags used by this model specific register.
+ using flags = ValueType;
+
+ //! Set one or more flags in this model specific register.
+ //!
+ //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to
+ //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function
+ //! will perform no additional checks, and may, by extension, crash the system.
+ //!
+ //! @param flag One or a combination of flags to be set in the model specific register.
+ auto static set(flags flag) -> void
+ {
+ auto current = Derived::read();
+ current |= flag;
+ Derived::write(current);
+ }
+
+ //! Clear one or more flags in this model specific register.
+ //!
+ //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to
+ //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function
+ //! will perform no additional checks, and may, by extension, crash the system.
+ //!
+ //! @param flag One or a combination of flags to be cleared in the model specific register.
+ auto static clear(flags flag) -> void
+ {
+ auto current = Derived::read();
+ current &= ~flag;
+ Derived::write(current);
+ }
+
+ //! Test one or more flags in this model specific register
+ //!
+ //! @param flag One or a combination of flags to test for.
+ auto test(flags flag) -> flags
+ {
+ return Derived::read() & flag;
+ }
+ };
+
+ //! A model specific register (MSR)
+ //!
+ //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations.
+ //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in
+ //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in
+ //! an invalid/undefined state.
+ //!
+ //! @tparam Number The register number of this MSR
+ //! @tparam ValueType The value type of this MSR
+ template<std::uint32_t Number, typename ValueType>
+ struct model_specific_register
+ : model_specific_register_with_flags<model_specific_register<Number, ValueType>, ValueType>
+ {
+ //! A raw MSR value, comprising two halfs.
+ //!
+ //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs.
+ struct raw_value
+ {
+ std::uint32_t low_half; //!< The lower half of the register value
+ std::uint32_t high_half; //!< The upper half of the register value
+ };
+
+ //! Read the current value of this MSR.
+ //!
+ //! @return The current value of this MSR.
+ auto static read() -> ValueType
+ {
+ auto raw = raw_value{};
+ asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number));
+ return static_cast<ValueType>(std::bit_cast<std::uint64_t>(raw));
+ }
+
+ //! Write a new value to this MSR.
+ //!
+ //! @param value The new value for this MSR.
+ auto static write(ValueType value) -> void
+ {
+ auto raw = std::bit_cast<raw_value>(static_cast<std::uint64_t>(value));
+ asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number));
+ }
+ };
+
+} // namespace teachos::cpu::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/cpu/registers.hpp b/arch/x86_64/include/x86_64/cpu/registers.hpp
new file mode 100644
index 0000000..8eb89e3
--- /dev/null
+++ b/arch/x86_64/include/x86_64/cpu/registers.hpp
@@ -0,0 +1,30 @@
+#ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP
+#define TEACHOS_X86_64_CPU_REGISTERS_HPP
+
+#include "x86_64/cpu/control_register.hpp" // IWYU pragma: export
+#include "x86_64/cpu/model_specific_register.hpp" // IWYU pragma: export
+
+namespace teachos::cpu::x86_64
+{
+
+ //! Configuration Register 0.
+ //!
+ //! This configuration register holds various control flags to configure the configure the basic operation of the CPU.
+ using cr0 = control_register<cr0_flags, &impl::cr0_asm>;
+
+ //! Configuration Register 2.
+ //!
+ //! This configuration register holds the memory address the access to which has triggered the most recent page fault.
+ using cr2 = control_register<memory::linear_address, &impl::cr2_asm>;
+
+ //! Configuration Register 3.
+ //!
+ //! This register holds the configuration of the virtual memory protection configuration.
+ using cr3 = control_register<cr3_value, &impl::cr3_asm>;
+
+ //! The I32_EFER (Extended Feature Enable Register) MSR
+ using i32_efer = model_specific_register<ia32_efer_number, ia32_efer_flags>;
+
+} // namespace teachos::cpu::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/device_io/port_io.hpp b/arch/x86_64/include/x86_64/device_io/port_io.hpp
new file mode 100644
index 0000000..c3e5271
--- /dev/null
+++ b/arch/x86_64/include/x86_64/device_io/port_io.hpp
@@ -0,0 +1,101 @@
+#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP
+#define TEACHOS_X86_64_IO_PORT_IO_HPP
+
+#include <array>
+#include <concepts>
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+#include <type_traits>
+
+namespace teachos::io::x86_64
+{
+
+ //! The requirements imposed on a type usable for port I/O.
+ template<typename ValueType>
+ concept port_io_type = requires {
+ requires sizeof(ValueType) == 1 || sizeof(ValueType) == 2 || sizeof(ValueType) == 4;
+ requires std::default_initializable<ValueType>;
+ std::bit_cast<ValueType>(
+ std::conditional_t<sizeof(ValueType) == 1, std::byte,
+ std::conditional_t<sizeof(ValueType) == 2, std::uint16_t, std::uint32_t>>{});
+ };
+
+ template<typename Derived>
+ struct port_read
+ {
+ //! Read from the I/O port.
+ //!
+ //! @return The data read from the I/O port.
+ auto static read() noexcept
+ {
+ auto data = typename Derived::value_type{};
+ asm volatile((code[Derived::size / 2])
+ : [data] "=m"(data)
+ : [port] "i"(Derived::size)
+ : "dx", (Derived::data_register));
+ return data;
+ }
+
+ private:
+ //! The assembly templates used for reading from an I/O port.
+ constexpr auto static code = std::array{
+ std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"},
+ std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"},
+ std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"},
+ };
+ };
+
+ template<typename Derived>
+ struct port_write
+ {
+ //! Write data to the I/O port.
+ //!
+ //! @param data The data to write to the I/O port.
+ auto static write(std::same_as<typename Derived::value_type> auto data) noexcept -> void
+ {
+ asm volatile((code[Derived::size / 2])
+ :
+ : [port] "i"(Derived::address), [data] "im"(data)
+ : "dx", (Derived::data_register));
+ }
+
+ private:
+ //! The assembly templates used for writing to an I/O port.
+ constexpr auto static code = std::array{
+ std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%al, %%dx"},
+ std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%ax, %%dx"},
+ std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%eax, %%dx"},
+ };
+ };
+
+ //! An I/O port of a given size at a given address.
+ //!
+ //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte
+ //! to double-word sized transfers.
+ //!
+ //! @tparam Address The address (port number) of the I/O port.
+ //! @tparam Size The size (in bytes) of the I/O port.
+ //! @tparam Features The features (readable, writeable)
+ template<std::uint16_t Address, port_io_type ValueType, template<typename> typename... Features>
+ requires(sizeof...(Features) > 0)
+ struct port : Features<port<Address, ValueType, Features...>>...
+ {
+ //! The type of the data of this port.
+ using value_type = ValueType;
+
+ //! The address of this I/O port.
+ constexpr auto static address = Address;
+
+ //! The size of this I/O port.
+ constexpr auto static size = sizeof(value_type);
+
+ //! The register clobbered by the I/O operation.
+ constexpr auto static data_register = size == 1 ? std::string_view{"al"}
+ : size == 2 ? std::string_view{"ax"}
+ : std::string_view{"eax"};
+ };
+
+} // namespace teachos::io::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp
new file mode 100644
index 0000000..90ac878
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp
@@ -0,0 +1,68 @@
+#ifndef TEACHOS_X86_64_BUFFERED_ALLOCATOR_HPP
+#define TEACHOS_X86_64_BUFFERED_ALLOCATOR_HPP
+
+#include "kapi/memory.hpp"
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <optional>
+
+namespace teachos::memory::x86_64
+{
+
+ template<std::size_t BufferSize>
+ struct buffered_allocator : frame_allocator
+ {
+ explicit buffered_allocator(frame_allocator * underlying)
+ : m_underlying{underlying}
+ {
+ std::ranges::generate(m_pool, [this] { return m_underlying->allocate(); });
+ }
+
+ buffered_allocator(buffered_allocator const &) = delete;
+ buffered_allocator(buffered_allocator && other) noexcept = delete;
+
+ ~buffered_allocator() override
+ {
+ std::ranges::for_each(m_pool, [this](auto const & maybe_frame) {
+ if (maybe_frame)
+ {
+ m_underlying->release(*maybe_frame);
+ }
+ });
+ }
+
+ auto operator=(buffered_allocator const &) = delete;
+ auto operator=(buffered_allocator &&) = delete;
+
+ auto allocate() noexcept -> std::optional<frame> override
+ {
+ auto found = std::ranges::find_if(m_pool, [](auto const & candidate) { return candidate.has_value(); });
+ if (found == std::end(m_pool))
+ {
+ return m_underlying->allocate();
+ }
+ auto frame = found->value();
+ found->reset();
+ return frame;
+ }
+
+ auto release(frame frame) -> void override
+ {
+ auto found = std::ranges::find_if(m_pool, [](auto const & candidate) { return !candidate; });
+ if (found == std::end(m_pool))
+ {
+ return m_underlying->release(frame);
+ }
+ (*found) = frame;
+ }
+
+ private:
+ frame_allocator * m_underlying;
+ std::array<std::optional<frame>, BufferSize> m_pool{};
+ };
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp
new file mode 100644
index 0000000..5b9c2fd
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp
@@ -0,0 +1,32 @@
+#ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP
+#define TEACHOS_X86_64_KERNEL_MAPPER_HPP
+
+#include "kapi/memory.hpp"
+
+#include <elf/format.hpp>
+#include <elf/section_header.hpp>
+#include <multiboot2/information.hpp>
+
+#include <string_view>
+
+namespace teachos::memory::x86_64
+{
+
+ struct kernel_mapper
+ {
+ using section_header_type = elf::section_header<elf::format::elf64>;
+
+ explicit kernel_mapper(multiboot2::information_view const * mbi);
+
+ auto remap_kernel(page_mapper & mapper) -> void;
+
+ private:
+ auto map_section(section_header_type const & section, std::string_view name, page_mapper & mapper) -> void;
+
+ multiboot2::information_view const * m_mbi;
+ std::uintptr_t m_kernel_load_base;
+ };
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp b/arch/x86_64/include/x86_64/memory/mmu.hpp
index f3e58a6..323d18a 100644
--- a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp
+++ b/arch/x86_64/include/x86_64/memory/mmu.hpp
@@ -1,9 +1,9 @@
-#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP
-#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP
+#ifndef TEACHOS_X86_64_MEMORY_MMU_HPP
+#define TEACHOS_X86_64_MEMORY_MMU_HPP
-#include "arch/memory/paging/virtual_page.hpp"
+#include "kapi/memory/address.hpp"
-namespace teachos::arch::kernel::cpu
+namespace teachos::memory::x86_64
{
/**
* @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained
@@ -12,7 +12,7 @@ namespace teachos::arch::kernel::cpu
* @param address Memory address, which will be used to determine the contained page and flush the TLB entry for
* that page.
*/
- auto tlb_flush(memory::paging::virtual_address address) -> void;
+ auto tlb_flush(linear_address address) -> void;
/**
* @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables.
@@ -22,6 +22,6 @@ namespace teachos::arch::kernel::cpu
*/
auto tlb_flush_all() -> void;
-} // namespace teachos::arch::kernel::cpu
+} // namespace teachos::memory::x86_64
-#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp
new file mode 100644
index 0000000..71ba5b7
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/page_table.hpp
@@ -0,0 +1,341 @@
+#ifndef TEACHOS_X86_64_PAGE_TABLE_HPP
+#define TEACHOS_X86_64_PAGE_TABLE_HPP
+
+#include "kapi/memory.hpp"
+
+#include "x86_64/memory/page_utilities.hpp"
+
+#include <kstd/ext/bitfield_enum>
+
+#include <array>
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+namespace teachos::memory::x86_64
+{
+
+ //! A table containing page mapping entries.
+ //!
+ //! Page tables exist in a multi-level hierarchy and are used to map pages (virtual memory) onto frames (physical
+ //! memory). Conceptually, pages represent the data found in a virtual address space, while frames represent their
+ //! storage. Only a level 1 page table maps an actual page onto a frame. All other page tables on higher levels do not
+ //! map payload pages, but rather their subordinate page tables.
+ struct page_table
+ {
+ //! An entry in a page table.
+ //!
+ //! A page table entry is a combination of a frame number and a set of flags that determine the properties and
+ //! access rights to a mapped page. Entries at a higher level in the page hierarchy do not map a page directly,
+ //! unless that page is marked as huge on the relevant level, but rather map the next lower page table.
+ struct entry
+ {
+ //! Flags marking the state and configuration of an entry.
+ //!
+ //! An entry in a page table may have any combination of these flags active at the same time. The final flags of a
+ //! page are determined as the strictest combination (logical AND) of all flags along the hierarchy.
+ //!
+ //! @note This is a bitfield enum as defined by kstd::ext::bitfield_enum.
+ enum struct flags : std::uint64_t
+ {
+ empty = 0,
+ present = 1uz << 0, //!< The page is mapped.
+ writable = 1uz << 1, //!< The page is writable.
+ user_accessible = 1uz << 2, //!< The page is accessible in user mode.
+ write_through = 1uz << 3, //!< Any writes to the page must immediately hit memory.
+ disable_cache = 1uz << 4, //!< Any writes to the page must never be cached.
+ accessed = 1uz << 5, //!< The page was accessed.
+ dirty = 1uz << 6, //!< The page was written to.
+ huge_page = 1uz << 7, //!< The page is huge.
+ global = 1uz << 8, //!< The TLB entry for this page must not be flushed on context switches.
+ no_execute = 1uz << 63, //!< The data in this page must not be executed.
+ };
+
+ //! Construct an empty entry.
+ entry() = default;
+
+ //! Clear this entry, ensuring all information is set to zero.
+ //!
+ //! This effectively marks the page represented by this entry as not present. In addition, it also removes any
+ //! information about the frame referenced by this entry.
+ auto clear() noexcept -> void;
+
+ //! Check if the page represented by this entry is present.
+ //!
+ //! @note This function does not attempt to walk the page table hierarchy, but only performs a local check. This
+ //! means, that if the page is not mapped at a lower level, this will not be detected.
+ //!
+ //! @return @p true iff. the page is present at this level, @p false otherwise.
+ [[nodiscard]] auto present() const noexcept -> bool;
+
+ //! Check if the page represented by this entry is a huge page.
+ //!
+ //! @note The effective size of the page depends on the level of the page table containing this entry.
+ //!
+ //! @return @p true iff. the page is marked as being huge, @p false otherwise.
+ [[nodiscard]] auto huge() const noexcept -> bool;
+
+ //! Get all flags present in this entry.
+ //!
+ //! @return The flags that are currently set on this entry.
+ [[nodiscard]] auto all_flags() const noexcept -> flags;
+
+ //! Set all flags of this entry.
+ //!
+ //! @param flags The flags to apply to this entry.
+ auto all_flags(flags flags) noexcept -> void;
+
+ //! Add the given flags to the flags of this entry.
+ //!
+ //! @param rhs The flags to add to this entry's flags.
+ //! @return A reference to this entry.
+ auto operator|=(flags rhs) noexcept -> entry &;
+
+ //! Get the frame number associated with this entry, if the referenced page is present.
+ //!
+ //! @return an engaged std::optional iff. this entry maps a page, std::nullopt otherwise.
+ [[nodiscard]] auto frame() const noexcept -> std::optional<frame>;
+
+ //! Map this entry.
+ //!
+ //! @param frame The frame to map in this entry.
+ //! @param flags The flags to apply to this entry.
+ auto frame(struct frame frame, flags flags) noexcept -> void;
+
+ private:
+ //! A mask to retrieve, or exclude, the frame number from the raw entry.
+ //!
+ //! Page table entries in x86_64 are a compacted combination of the relevant flags and the frame number. This mask
+ //! represents the bits that make up the frame number in an entry.
+ constexpr auto static frame_number_mask{0x000f'ffff'ffff'f000uz};
+
+ //! The raw entry bytes.
+ //!
+ //! @see entry::frame_number_mask
+ std::uint64_t m_raw{};
+ };
+
+ //! The maximum number of entries in this table.
+ constexpr auto static entry_count{page::size / sizeof(entry)};
+
+ //! Get the entry at the given index.
+ //!
+ //! @warning This function will panic if the entry index is out of bounds.
+ //!
+ //! @param index The index of the desired entry.
+ //! @return A reference to the entry at the given index.
+ [[nodiscard]] auto operator[](std::size_t index) -> entry &;
+
+ //! @copydoc page_table::operator[]
+ [[nodiscard]] auto operator[](std::size_t index) const -> entry const &;
+
+ //! Clear the entire page table.
+ //!
+ //! This function effectively marks the page table as not mapping any pages.
+ auto clear() noexcept -> void;
+
+ //! Check if the page table is empty.
+ //!
+ //! @return @p true iff. this page table has no entries marked present, @p false otherwise.
+ [[nodiscard]] auto empty() const noexcept -> bool;
+
+ private:
+ std::array<entry, entry_count> m_entries{};
+ };
+
+ //! A recursively mapped page table.
+ //!
+ //! A page table in which at least one entry maps the same table. Recursive page tables allow for easy access to other
+ //! tables within the page mapping hierarchy, without having to map them prior to access, through careful construction
+ //! of linear addresses that pass through the same index multiple times.
+ template<std::size_t Level>
+ requires(Level > 0uz && Level < 5uz)
+ struct recursive_page_table : page_table
+ {
+ constexpr auto static next_level = Level - 1uz;
+ constexpr auto static recursive_index = 0776uz;
+
+ //! Get the next lower lever table.
+ //!
+ //! @param self The object type of this object.
+ //! @param index The index corresponding to the desired page map.
+ //! @return An engaged std::optional holding a pointer to the next lower page table iff. the next lower page table
+ //! at the desired index is present, std::nullopt otherwise.
+ [[nodiscard]] auto next(this auto && self, std::size_t index) noexcept
+ requires(next_level > 1)
+ {
+ return self.next_address(index).transform([](auto address) -> auto {
+ auto table_pointer = std::bit_cast<recursive_page_table<next_level> *>(address);
+ return &std::forward_like<decltype(self)>(*table_pointer);
+ });
+ }
+
+ //! @copydoc recursive_page_table::next
+ //!
+ //! @note This overload returns a non-hierarchical, or leaf, page table
+ [[nodiscard]] auto next(this auto && self, std::size_t index) noexcept
+ requires(next_level == 1)
+ {
+ return self.next_address(index).transform([](auto address) -> auto {
+ auto table_pointer = std::bit_cast<page_table *>(address);
+ return &std::forward_like<decltype(self)>(*table_pointer);
+ });
+ }
+
+ [[nodiscard]] auto translate(linear_address address) const -> std::optional<physical_address>
+ requires(Level == 4)
+ {
+ auto offset = address.raw() % page::size;
+ return translate(page::containing(address)).transform([offset](auto frame) -> auto {
+ return physical_address{frame.start_address().raw() + offset};
+ });
+ }
+
+ [[nodiscard]] auto translate(page page) const -> std::optional<frame>
+ requires(Level == 4)
+ {
+ auto pml3 = next(pml_index<4>(page));
+
+ if (!pml3)
+ {
+ return std::nullopt;
+ }
+
+ auto handle_huge_page = [&] -> std::optional<frame> {
+ auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; });
+ if (!pml3_entry)
+ {
+ return std::nullopt;
+ }
+ else if (pml3_entry->huge())
+ {
+ auto pml3_entry_frame = *pml3_entry->frame();
+ return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)};
+ }
+
+ auto pml2 = (*pml3)->next(pml_index<3>(page));
+ auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; });
+ if (!pml2_entry)
+ {
+ return std::nullopt;
+ }
+ else if (pml2_entry->huge())
+ {
+ auto pml2_entry_frame = *pml2_entry->frame();
+ return frame{pml2_entry_frame.number() + pml_index<1>(page)};
+ }
+
+ return std::nullopt;
+ };
+
+ return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); })
+ .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); })
+ .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); })
+ .or_else(handle_huge_page);
+ }
+
+ private:
+ //! The number of address bits used to represent the page index per level.
+ constexpr auto static level_bits = 9;
+ //! The highest address bit.
+ constexpr auto static high_bit = 48;
+ //! The number of bits representing the offset into a page.
+ constexpr auto static offset_bits = 12;
+
+ //! Calculate the recursive address of the next lower page table.
+ //!
+ //! @param index The index of the desired page table.
+ //! @return An engaged std::optional holding the address of the new lower page table iff. the next lower page table
+ //! at the desired index is present, std::nullopt otherwise.
+ [[nodiscard]] auto next_address(std::size_t index) const noexcept -> std::optional<std::uintptr_t>
+ {
+ if (auto entry = (*this)[index]; entry.present() && !entry.huge())
+ {
+ auto this_address = std::bit_cast<std::uintptr_t>(this);
+ auto next_address = (this_address << level_bits) | 1uz << high_bit | (index << offset_bits);
+ return next_address;
+ }
+
+ return std::nullopt;
+ }
+ };
+
+} // namespace teachos::memory::x86_64
+
+namespace kstd::ext
+{
+ template<>
+ struct is_bitfield_enum<teachos::memory::x86_64::page_table::entry::flags> : std::true_type
+ {
+ };
+} // namespace kstd::ext
+
+namespace teachos::memory::x86_64
+{
+
+ constexpr auto to_mapper_flags(page_table::entry::flags flags) -> page_mapper::flags
+ {
+ using table_flags = page_table::entry::flags;
+ using mapper_flags = page_mapper::flags;
+
+ auto result = mapper_flags{};
+
+ if ((flags & table_flags::no_execute) == table_flags::empty)
+ {
+ result |= mapper_flags::executable;
+ }
+
+ if ((flags & table_flags::writable) != table_flags::empty)
+ {
+ result |= mapper_flags::writable;
+ }
+
+ if ((flags & table_flags::disable_cache) != table_flags::empty)
+ {
+ result |= mapper_flags::uncached;
+ }
+
+ if ((flags & table_flags::user_accessible) == table_flags::empty)
+ {
+ result |= mapper_flags::supervisor_only;
+ }
+
+ return result;
+ }
+
+ constexpr auto to_table_flags(page_mapper::flags flags) -> page_table::entry::flags
+ {
+ using table_flags = page_table::entry::flags;
+ using mapper_flags = page_mapper::flags;
+
+ auto result = table_flags{};
+
+ if ((flags & mapper_flags::executable) == mapper_flags::empty)
+ {
+ result |= table_flags::no_execute;
+ }
+
+ if ((flags & mapper_flags::writable) != mapper_flags::empty)
+ {
+ result |= table_flags::writable;
+ }
+
+ if ((flags & mapper_flags::uncached) != mapper_flags::empty)
+ {
+ result |= table_flags::disable_cache;
+ }
+
+ if ((flags & mapper_flags::supervisor_only) != mapper_flags::empty)
+ {
+ result |= table_flags::user_accessible;
+ }
+
+ return result;
+ }
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/page_utilities.hpp b/arch/x86_64/include/x86_64/memory/page_utilities.hpp
new file mode 100644
index 0000000..efd1b80
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/page_utilities.hpp
@@ -0,0 +1,22 @@
+#ifndef TEACHOS_X86_64_PAGE_UTILITIES_HPP
+#define TEACHOS_X86_64_PAGE_UTILITIES_HPP
+
+#include "kapi/memory.hpp"
+
+#include <cstddef>
+
+namespace teachos::memory::x86_64
+{
+
+ template<std::size_t Level>
+ requires(Level > 0uz && Level < 5uz)
+ constexpr auto pml_index(page page) noexcept -> std::size_t
+ {
+ constexpr auto shift_width = (Level - 1) * 9;
+ constexpr auto index_mask = 0x1ffuz;
+ return page.number() >> shift_width & index_mask;
+ }
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/paging_root.hpp b/arch/x86_64/include/x86_64/memory/paging_root.hpp
new file mode 100644
index 0000000..47ee2f9
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp
@@ -0,0 +1,27 @@
+#ifndef TEACHOS_X86_64_PAGING_ROOT_HPP
+#define TEACHOS_X86_64_PAGING_ROOT_HPP
+
+#include "x86_64/memory/page_table.hpp"
+
+namespace teachos::memory::x86_64
+{
+
+ //! The active, recursively mapped, root map (e.g. PML4)
+ struct paging_root : recursive_page_table<4>
+ {
+ auto static get() -> paging_root *;
+
+ paging_root(paging_root const &) = delete;
+ paging_root(paging_root &&) = delete;
+ auto operator=(paging_root const &) -> paging_root & = delete;
+ auto operator=(paging_root &&) -> paging_root & = delete;
+
+ ~paging_root() = delete;
+
+ private:
+ paging_root() = default;
+ };
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp b/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp
new file mode 100644
index 0000000..dc52065
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp
@@ -0,0 +1,23 @@
+#ifndef TEACHOS_X86_64_RECURSIVE_PAGE_MAPPER_HPP
+#define TEACHOS_X86_64_RECURSIVE_PAGE_MAPPER_HPP
+
+#include "kapi/memory.hpp"
+
+namespace teachos::memory::x86_64
+{
+
+ struct recursive_page_mapper : page_mapper
+ {
+ explicit recursive_page_mapper(frame_allocator & allocator);
+
+ auto map(page page, frame frame, flags flags) -> std::byte * override;
+ auto unmap(page page) -> void override;
+ auto try_unmap(page page) noexcept -> bool override;
+
+ private:
+ frame_allocator * m_allocator;
+ };
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/memory/region_allocator.hpp b/arch/x86_64/include/x86_64/memory/region_allocator.hpp
new file mode 100644
index 0000000..84b7a94
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp
@@ -0,0 +1,79 @@
+#ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP
+#define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP
+
+#include "kapi/memory/address.hpp"
+#include "kapi/memory/frame.hpp"
+#include "kapi/memory/frame_allocator.hpp"
+
+#include <multiboot2/information.hpp>
+
+#include <optional>
+#include <utility>
+
+namespace teachos::memory::x86_64
+{
+ //! A simple, memory-region based frame allocator.
+ //!
+ //! This frame allocator linearly allocates frames that are in available memory regions. It automatically skips any
+ //! frames occupied by the kernel image or any bootloader provided data.
+ //!
+ //! @note This allocator will never release frames.
+ struct region_allocator final : frame_allocator
+ {
+ struct memory_information
+ {
+ //! The memory range occupied by the loaded kernel image.
+ //!
+ //! This includes all sections that are marked as occupying space in the kernel executable. The internal structure
+ //! of this area is more described in a more fine-grained manner by the ELF symbol information provided in the
+ //! Multiboot2 information by the loader.
+ std::pair<physical_address, physical_address> image_range;
+
+ //! The memory range occupied by the loader supplied Multiboot2 information structure.
+ //!
+ //! In general, this information is allocated somewhere in the range of the loaded image, but the loader protocol
+ //! does not guarantee this. It is thus imperative to be able to handle the cases where the loader chooses to
+ //! allocate the information structure outside of the image range.
+ std::pair<physical_address, physical_address> mbi_range;
+
+ //! The loader supplied map of memory regions.
+ //!
+ //! These include available, unavailable, and reclaimable regions. In general, only frames that are located in
+ //! non-reserved (as in available) regions should be allocated for page storage.
+ multiboot2::memory_map memory_map;
+ };
+
+ using region = multiboot2::memory_map::region;
+
+ //! Construct a new allocator using the provided memory information
+ //!
+ //! @param information The description of the detected memory regions as well as regions that are already occupied.
+ explicit region_allocator(memory_information const & information);
+
+ //! @copydoc frame_allocator::allocate
+ //!
+ //! @note As long as free frames are available, successive calls to this implementation are guaranteed to yield
+ //! frames in ascending order.
+ auto allocate() noexcept -> std::optional<frame> override;
+
+ //! @copydoc frame_allocator::release
+ //!
+ //! @note This implementation will never actually release any frames.
+ auto release(frame frame) -> void override;
+
+ private:
+ //! Find the next memory area and write it into current_area.
+ auto choose_next_area() -> void;
+
+ frame m_next_frame; //!< The next available frame.
+ std::optional<region> m_current_region; //!< The memory region currently used for allocation
+ multiboot2::memory_map m_memory_map; //!< The boot loader supplied memory map.
+ frame m_kernel_start; //!< The start of the kernel image in physical memory.
+ frame m_kernel_end; //!< The end of the kernel image in physical memory.
+ frame m_multiboot_start; //!< The start of the Multiboot2 information in physical memory.
+ frame m_multiboot_end; //!< The end of the Multiboot2 information in physical memory.
+ };
+
+} // namespace teachos::memory::x86_64
+
+#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP
diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp
new file mode 100644
index 0000000..835e2df
--- /dev/null
+++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp
@@ -0,0 +1,66 @@
+#ifndef TEACHOS_X86_64_SCOPED_MAPPING_HPP
+#define TEACHOS_X86_64_SCOPED_MAPPING_HPP
+
+#include "kapi/memory.hpp"
+
+#include "x86_64/memory/page_table.hpp"
+
+namespace teachos::memory::x86_64
+{
+
+ //! A page mapping that, if established, maps a given frame to a given unused page, unmapping it on destruction. It
+ //! allows for an easy way to quickly map a page that is not required to be mapped forever. When mapping a frame, new
+ //! page tables may be allocated. On destruction, these pages tables, or rather their respective frames, will be
+ //! released again.
+ struct scoped_mapping
+ {
+ //! Copying a scoped mapping would be meaningless.
+ scoped_mapping(scoped_mapping const &) noexcept = delete;
+
+ //! Adopt an existing scoped mapping, transferring mapping ownership to this new object.
+ scoped_mapping(scoped_mapping &&) noexcept;
+
+ //! Construct a new scoped mapping, which can be used to map a frame to the given unused page.
+ //! @param page An unused page. If the page is already mapped, this constructor will panic.
+ //! @param mapper The page mapper to use for mapping and unmapping of the page.
+ explicit scoped_mapping(page page, page_mapper & mapper);
+
+ //! Unmap the mapped frame if one was mapped.
+ //! @note Any page tables that were allocated to support the mapping will be released.
+ ~scoped_mapping() noexcept;
+
+ //! Copying a scoped mapping would be meaningless.
+ auto operator=(scoped_mapping const &) -> scoped_mapping = delete;
+
+ //! Adopt an existing scoped mapping, swapping mapping ownerships between the objects.
+ auto operator=(scoped_mapping &&) noexcept -> scoped_mapping &;
+
+ //! Map the given frame with the given flags.
+ //! @note If a mapping has already been established, this function will panic
+ //! @param frame A frame to map.
+ //! @param flags The flags, besides the present flag, to apply to the mapping.
+ //! @return A pointer to the first byte of the mapped frame.
+ auto map(frame frame, page_table::entry::flags flags) -> std::byte *;
+
+ //! Map the given frame, returning a typed pointer.
+ template<typename DataType>
+ auto map_as(frame frame, page_table::entry::flags flags) -> DataType *
+ {
+ return std::bit_cast<DataType *>(map(frame, flags));
+ }
+
+ //! Unmap the mapped frame.
+ //! @note If no frame was ever mapped, this function will panic.
+ auto unmap() -> void;
+
+ friend auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void;
+
+ private:
+ page m_page;
+ page_mapper * m_mapper;
+ bool m_mapped;
+ };
+
+} // namespace teachos::memory::x86_64
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/vga/crtc.hpp b/arch/x86_64/include/x86_64/vga/crtc.hpp
new file mode 100644
index 0000000..d4b4f51
--- /dev/null
+++ b/arch/x86_64/include/x86_64/vga/crtc.hpp
@@ -0,0 +1,39 @@
+#ifndef TEACHOS_X86_64_VGA_IO_HPP
+#define TEACHOS_X86_64_VGA_IO_HPP
+
+#include "x86_64/device_io/port_io.hpp"
+
+#include <cstddef>
+
+namespace teachos::vga::x86_64::crtc
+{
+ namespace io = io::x86_64;
+
+ /**
+ * @brief The address port of the CRT Controller.
+ */
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
+ using address = io::port<0x3d4, std::byte, io::port_write>;
+
+ /**
+ * @brief The data port of the CRT Controller.
+ */
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
+ using data = io::port<0x3d5, std::byte, io::port_read, io::port_write>;
+
+ namespace registers
+ {
+ /**
+ * @brief The address of the Cursor Start register of the CRTC.
+ */
+ [[maybe_unused]] constexpr auto cursor_start = std::byte{0x0a};
+
+ /**
+ * @brief The address of the Cursor End register of the CRTC.
+ */
+ [[maybe_unused]] constexpr auto cursor_end = std::byte{0x0b};
+ } // namespace registers
+
+} // namespace teachos::vga::x86_64::crtc
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp
new file mode 100644
index 0000000..bb593e7
--- /dev/null
+++ b/arch/x86_64/include/x86_64/vga/text.hpp
@@ -0,0 +1,178 @@
+#ifndef TEACHOS_X86_64_VIDEO_VGA_TEXT_HPP
+#define TEACHOS_X86_64_VIDEO_VGA_TEXT_HPP
+
+#include "kapi/cio.hpp"
+
+#include <cstdint>
+#include <span>
+#include <string_view>
+
+namespace teachos::vga::x86_64::text
+{
+ /**
+ * @brief The colors available in the standard VGA text mode.
+ */
+ enum struct color : std::uint8_t
+ {
+ black, ///< Equivalent to HTML color \#000000.
+ blue, ///< Equivalent to HTML color \#0000AA.
+ green, ///< Equivalent to HTML color \#00AA00.
+ cyan, ///< Equivalent to HTML color \#00AAAA.
+ red, ///< Equivalent to HTML color \#AA0000.
+ purple, ///< Equivalent to HTML color \#AA00AA.
+ brown, ///< Equivalent to HTML color \#AA5500.
+ gray, ///< Equivalent to HTML color \#AAAAAA.
+ };
+
+ /**
+ * @brief The foreground color modification flag.
+ */
+ enum struct foreground_flag : bool
+ {
+ none, ///< Apply no flag e.g., keep color as is.
+ intense, ///< Make the color more intense (usually brighter).
+ };
+
+ /**
+ * @brief The background color modification flag.
+ */
+ enum struct background_flag : bool
+ {
+ none, ///< Apply no flag e.g., keep color as is.
+ blink_or_bright, ///< Make the cell blink or more intense, dependent on the VGA configuration.
+ };
+
+ /**
+ * @brief The VGA text mode attribute.
+ *
+ * @note In the text mode of VGA, every code point being presented is followed by an attribute description. This
+ * allows for the modification of how the relevant "cell" is presented.
+ *
+ * @see vga::text::foreground_flag
+ * @see vga::text::background_flag
+ */
+ struct attribute
+ {
+ color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point.
+ enum foreground_flag foreground_flag : 1; ///< The foreground color modification flag of the cell.
+ color background_color : 3; ///< The background color of the cell.
+ enum background_flag background_flag : 1; ///< The background color modification flag of the cell.
+ };
+
+ static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte.");
+
+ /**
+ * @brief Commonly used VGA text mode attributes.
+ */
+ namespace common_attributes
+ {
+ /**
+ * @brief Make the affected cell display with a gray foreground and black background.
+ */
+ [[maybe_unused]] constexpr auto gray_on_black = attribute{.foreground_color = color::gray,
+ .foreground_flag = foreground_flag::none,
+ .background_color = color::black,
+ .background_flag = background_flag::none};
+
+ /**
+ * @brief Make the affected cell display with a green foreground and black background.
+ */
+ [[maybe_unused]] constexpr auto green_on_black = attribute{.foreground_color = color::green,
+ .foreground_flag = foreground_flag::none,
+ .background_color = color::black,
+ .background_flag = background_flag::none};
+
+ /**
+ * @brief Make the affected cell display with a green foreground and black background.
+ */
+ [[maybe_unused]] constexpr auto red_on_black = attribute{.foreground_color = color::red,
+ .foreground_flag = foreground_flag::none,
+ .background_color = color::black,
+ .background_flag = background_flag::none};
+
+ /**
+ * @brief Make the affected cell display with a white (gray + intense) foreground and red background.
+ */
+ [[maybe_unused]] constexpr auto white_on_red = attribute{.foreground_color = color::gray,
+ .foreground_flag = foreground_flag::intense,
+ .background_color = color::red,
+ .background_flag = background_flag::none};
+ } // namespace common_attributes
+
+ struct device final : teachos::cio::output_device
+ {
+ device();
+
+ /**
+ * @brief Clear the VGA text mode buffer.
+ *
+ * @note This function also resets the text mode buffer pointer.
+ *
+ * @param attribute The attribute to "clear" the screen with.
+ */
+ auto clear(attribute attribute = common_attributes::gray_on_black) -> void;
+
+ /**
+ * @brief Enable or disable the VGA text mode cursor.
+ *
+ * @param enabled Whether or not to enable the cursors.
+ */
+ auto cursor(bool enabled) -> void;
+
+ auto write(std::string_view text) -> void override
+ {
+ write(text, common_attributes::green_on_black);
+ }
+ auto writeln(std::string_view text) -> void override
+ {
+ writeln(text, common_attributes::green_on_black);
+ }
+ auto write_error(std::string_view text) -> void override
+ {
+ write(text, common_attributes::red_on_black);
+ }
+ auto writeln_error(std::string_view text) -> void override
+ {
+ writeln(text, common_attributes::red_on_black);
+ }
+
+ private:
+ using glyph = std::pair<char, std::byte>;
+
+ /**
+ * @brief Move the cursor to a new line, scrolling the buffer if necessary.
+ */
+ auto newline() -> void;
+
+ /**
+ * @brief Write a string of code points to the VGA text buffer.
+ *
+ * @note This function also updates the text mode buffer pointer.
+ *
+ * @param code_points A string of (8-bit) code points to write to the VGA text mode buffer.
+ * @param attribute The attribute to apply to the written sequence of code points.
+ * @see vga::text::attribute
+ */
+ auto write(std::string_view code_points, attribute attribute) -> void;
+
+ auto write(char code_point, attribute attribute) -> void;
+
+ /**
+ * @brief Write a string of code points followed by a newline to the VGA text buffer.
+ *
+ * @note This function also updates the text mode buffer pointer.
+ *
+ * @param code_points A string of (8-bit) code points to write to the VGA text mode buffer.
+ * @param attribute The attribute to apply to the written sequence of code points.
+ * @see vga::text::attribute
+ */
+ auto writeln(std::string_view code_points, attribute attribute) -> void;
+
+ std::span<glyph> static const buffer;
+
+ std::size_t m_position{};
+ };
+
+} // namespace teachos::vga::x86_64::text
+
+#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp
index 07110c8..07110c8 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp
index 5104c36..5104c36 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp
index b388e0e..b388e0e 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp
index 7fe933b..7fe933b 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp
index e45bcf4..e45bcf4 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp
index 2a7704e..ea8c145 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp
@@ -96,9 +96,9 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
private:
uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from.
- uint16_t _index : 13 =
- {}; ///< Index into the local or global descriptor table. Processor multiplies the index value by 16 (number of
- ///< bytes in segment descriptor) and adds the result to the base address.
+ uint16_t _index
+ : 13 = {}; ///< Index into the local or global descriptor table. Processor multiplies the index value by 16
+ ///< (number of bytes in segment descriptor) and adds the result to the base address.
};
} // namespace teachos::arch::context_switching::interrupt_descriptor_table
diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/pre/include/arch/context_switching/main.hpp
index f8477ea..f8477ea 100644
--- a/arch/x86_64/include/arch/context_switching/main.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/main.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/access_byte.hpp
index 7450330..7450330 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/access_byte.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp
index e24b988..e24b988 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp
index 44f2692..44f2692 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp
index 292ff70..292ff70 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp
index 933fb4d..933fb4d 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp
index 40bcc8a..40bcc8a 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp
index 8770b81..8770b81 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp
diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp
index d4aa5e8..d4aa5e8 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp
diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp
index 59adc13..f507c61 100644
--- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp
@@ -41,7 +41,10 @@ namespace teachos::arch::context_switching::syscall
* @param e Error code that was returned by the syscall.
* @return Return true if there was no error and false otherwise.
*/
- constexpr bool operator!(error e) { return e == error::OK; }
+ constexpr bool operator!(error e)
+ {
+ return e == error::OK;
+ }
/**
* @brief Maximum amount of arguments that can be passed to a syscall. Default value is 0 and arguments are only ever
diff --git a/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp
index 8cb468a..8cb468a 100644
--- a/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp
diff --git a/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp
index 2e7bcd1..2e7bcd1 100644
--- a/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp
+++ b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp
diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/pre/include/arch/exception_handling/assert.hpp
index 1286768..1286768 100644
--- a/arch/x86_64/include/arch/exception_handling/assert.hpp
+++ b/arch/x86_64/pre/include/arch/exception_handling/assert.hpp
diff --git a/arch/x86_64/include/arch/exception_handling/panic.hpp b/arch/x86_64/pre/include/arch/exception_handling/panic.hpp
index 6a2404c..6a2404c 100644
--- a/arch/x86_64/include/arch/exception_handling/panic.hpp
+++ b/arch/x86_64/pre/include/arch/exception_handling/panic.hpp
diff --git a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp b/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp
index 15b35c1..15b35c1 100644
--- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp
+++ b/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/call.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp
index 3c43304..3c43304 100644
--- a/arch/x86_64/include/arch/kernel/cpu/call.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp
index 68b950d..68b950d 100644
--- a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp
index cb800d0..cb800d0 100644
--- a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/if.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp
index 48707dc..48707dc 100644
--- a/arch/x86_64/include/arch/kernel/cpu/if.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp
index 99d6378..99d6378 100644
--- a/arch/x86_64/include/arch/kernel/cpu/msr.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp
index a236452..a236452 100644
--- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp
diff --git a/arch/x86_64/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp
index 7c856f1..7c856f1 100644
--- a/arch/x86_64/include/arch/kernel/cpu/tr.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp
diff --git a/arch/x86_64/include/arch/kernel/halt.hpp b/arch/x86_64/pre/include/arch/kernel/halt.hpp
index 377acc0..377acc0 100644
--- a/arch/x86_64/include/arch/kernel/halt.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/halt.hpp
diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/pre/include/arch/kernel/main.hpp
index a13e5f4..a13e5f4 100644
--- a/arch/x86_64/include/arch/kernel/main.hpp
+++ b/arch/x86_64/pre/include/arch/kernel/main.hpp
diff --git a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/bump_allocator.hpp
index 011f45c..011f45c 100644
--- a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp
+++ b/arch/x86_64/pre/include/arch/memory/heap/bump_allocator.hpp
diff --git a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp
index c98c130..480b1d0 100644
--- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp
+++ b/arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp
@@ -37,7 +37,7 @@ namespace teachos::arch::memory::heap
*
* @param new_type Type of the heap allocation implementation we want to instantiate
*/
- static auto register_heap_allocator(heap_allocator_type new_type) -> void;
+ auto static register_heap_allocator(heap_allocator_type new_type) -> void;
/**
* @brief Allocates the given amount of memory and returns the pointer to the start of the allocatable memory area.
@@ -46,7 +46,7 @@ namespace teachos::arch::memory::heap
* @param size Amount of bytes that should be allocated
* @return void* Pointer to the start of the allocatable memory area
*/
- static auto kmalloc(std::size_t size) -> void *;
+ auto static kmalloc(std::size_t size) -> void *;
/**
* @brief Deallocated all memory associated with the memory area starting from the given pointer address.
@@ -54,7 +54,7 @@ namespace teachos::arch::memory::heap
*
* @param pointer Previously allocated memory area, that should now be freed
*/
- static auto kfree(void * pointer) noexcept -> void;
+ auto static kfree(void * pointer) noexcept -> void;
/**
* @brief Allocates the given amount of memory and returns the pointer to the start of the allocatable memory area.
@@ -64,7 +64,7 @@ namespace teachos::arch::memory::heap
* @return void* Pointer to the start of the allocatable memory area
*/
[[gnu::section(".user_text")]]
- static auto malloc(std::size_t size) -> void *;
+ auto static malloc(std::size_t size) -> void *;
/**
* @brief Deallocated all memory associated with the memory area starting from the given pointer address.
@@ -73,11 +73,11 @@ namespace teachos::arch::memory::heap
* @param pointer Previously allocated memory area, that should now be freed
*/
[[gnu::section(".user_text")]]
- static auto free(void * pointer) noexcept -> void;
+ auto static free(void * pointer) noexcept -> void;
private:
- static heap_allocator * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory
- [[gnu::section(".user_data")]] static user_heap_allocator *
+ heap_allocator static * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory
+ [[gnu::section(".user_data")]] user_heap_allocator static *
user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory
/**
@@ -85,15 +85,14 @@ namespace teachos::arch::memory::heap
*
* @return Reference to the registered kernel heap allocation
*/
- static auto kernel() -> heap_allocator &;
+ auto static kernel() -> heap_allocator &;
/**
* @brief Either returns the previously registered heap allocated or halts further execution
*
* @return Reference to the registered user heap allocation
*/
- [[gnu::section(".user_text")]]
- static auto user() -> user_heap_allocator &;
+ [[gnu::section(".user_text")]] auto static user() -> user_heap_allocator &;
};
} // namespace teachos::arch::memory::heap
diff --git a/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp
index 420a1d3..6c25532 100644
--- a/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp
+++ b/arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp
@@ -5,10 +5,10 @@
namespace teachos::arch::memory::heap
{
- std::size_t constexpr KERNEL_HEAP_START = 0x100000000;
- std::size_t constexpr KERNEL_HEAP_SIZE = 100 * 1024;
- std::size_t constexpr USER_HEAP_START = 0x100019000; // Starts directly after kernel heap
- std::size_t constexpr USER_HEAP_SIZE = 100 * 1024;
+ constexpr std::size_t KERNEL_HEAP_START = 0x1'0000'0000;
+ constexpr std::size_t KERNEL_HEAP_SIZE = 100 * 1024;
+ constexpr std::size_t USER_HEAP_START = 0x1'0001'9000; // Starts directly after kernel heap
+ constexpr std::size_t USER_HEAP_SIZE = 100 * 1024;
/**
* @brief Heap allocator interface containing methods required to allocate and deallocate heap memory areas
diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp
index 582b4af..bb8b526 100644
--- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp
+++ b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp
@@ -3,7 +3,8 @@
#include "arch/memory/heap/heap_allocator.hpp"
#include "arch/memory/heap/memory_block.hpp"
-#include "arch/stl/mutex.hpp"
+
+#include <kstd/mutex.hpp>
namespace teachos::arch::memory::heap
{
@@ -43,7 +44,10 @@ namespace teachos::arch::memory::heap
*
* @return Smallest allocatable block of heap memory.
*/
- auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); }
+ constexpr auto min_allocatable_size() -> std::size_t
+ {
+ return sizeof(memory_block);
+ }
/**
* @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it.
@@ -112,7 +116,7 @@ namespace teachos::arch::memory::heap
std::size_t size) -> void;
memory_block * first; ///< First free entry in our memory.
- stl::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once.
+ kstd::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once.
};
} // namespace teachos::arch::memory::heap
diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp
index 9d1fb02..9d1fb02 100644
--- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp
+++ b/arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp
diff --git a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp
index 6b1b7bb..15d8574 100644
--- a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp
+++ b/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp
@@ -2,7 +2,9 @@
#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_ALLOCATOR_HPP
#include "arch/memory/heap/memory_block.hpp"
-#include "arch/stl/mutex.hpp"
+
+// #include <kstd/mutex.hpp>
+#include <kstd/mutex.hpp>
#include <optional>
@@ -46,7 +48,10 @@ namespace teachos::arch::memory::heap
*
* @return Smallest allocatable block of heap memory.
*/
- [[gnu::section(".user_text")]] auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); }
+ [[gnu::section(".user_text")]] constexpr auto min_allocatable_size() -> std::size_t
+ {
+ return sizeof(memory_block);
+ }
/**
* @brief Checks if the given memory block is big enough and if it is allocates into the current block.
@@ -141,7 +146,7 @@ namespace teachos::arch::memory::heap
std::size_t size) -> void;
memory_block * first = {}; ///< First free entry in our memory.
- stl::mutex mutex = {}; ///< Mutex to ensure only one thread calls allocate or deallocate at once.
+ kstd::mutex mutex = {}; ///< Mutex to ensure only one thread calls allocate or deallocate at once.
};
} // namespace teachos::arch::memory::heap
diff --git a/arch/x86_64/include/arch/user/main.hpp b/arch/x86_64/pre/include/arch/user/main.hpp
index c168a1f..c168a1f 100644
--- a/arch/x86_64/include/arch/user/main.hpp
+++ b/arch/x86_64/pre/include/arch/user/main.hpp
diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp
index 28f289c..28f289c 100644
--- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp
+++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp
diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp
index d36a4c1..f3b9d5e 100644
--- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp
+++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp
@@ -13,5 +13,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
return (std::bitset<8U>{_flags} & other) == other;
}
- auto idt_flags::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); }
+ auto idt_flags::operator|=(std::bitset<8U> other) -> void
+ {
+ _flags |= other.to_ulong();
+ }
} // namespace teachos::arch::context_switching::interrupt_descriptor_table
diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp
index 7aa0859..8640385 100644
--- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp
+++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp
@@ -33,7 +33,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &
{
// Interrupt Descriptor Table needs to be kept alive
- static interrupt_descriptor_table idt = create_interrupt_descriptor_table();
+ interrupt_descriptor_table static idt = create_interrupt_descriptor_table();
return idt;
}
diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp
index 7bcbae6..7bcbae6 100644
--- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp
+++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp
diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp
index a70e75d..a70e75d 100644
--- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp
+++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp
diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp
index 27f0a3b..25ba859 100644
--- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp
+++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp
@@ -7,9 +7,18 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
return (std::bitset<3U>{_flags} & other) == other;
}
- auto segment_selector::get_index() const -> uint16_t { return _index; }
+ auto segment_selector::get_index() const -> uint16_t
+ {
+ return _index;
+ }
- auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); }
+ auto segment_selector::operator|=(std::bitset<3U> other) -> void
+ {
+ _flags |= other.to_ulong();
+ }
- segment_selector::operator uint16_t() const { return *reinterpret_cast<uint16_t const *>(this); }
+ segment_selector::operator uint16_t() const
+ {
+ return *reinterpret_cast<uint16_t const *>(this);
+ }
} // namespace teachos::arch::context_switching::interrupt_descriptor_table
diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/pre/src/context_switching/main.cpp
index 9539428..3eb6dae 100644
--- a/arch/x86_64/src/context_switching/main.cpp
+++ b/arch/x86_64/pre/src/context_switching/main.cpp
@@ -13,20 +13,23 @@ namespace teachos::arch::context_switching
namespace
{
constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{
- 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL};
+ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL};
constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers,
KERNEL_CODE_SEGMENT_SELECTOR};
constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{
- 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER};
+ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER};
constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{
- 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER};
+ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER};
- auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); }
+ auto reload_gdtr() -> void
+ {
+ kernel::cpu::call(KERNEL_CODE_POINTER);
+ }
} // namespace
auto initialize_descriptor_tables() -> descriptor_tables
{
- static bool initalized = false;
+ bool static initalized = false;
if (!initalized)
{
diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp
index e31e021..fcc72cf 100644
--- a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp
+++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp
@@ -13,5 +13,8 @@ namespace teachos::arch::context_switching::segment_descriptor_table
return (std::bitset<8U>{_flags} & other) == other;
}
- auto access_byte::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); }
+ auto access_byte::operator|=(std::bitset<8U> other) -> void
+ {
+ _flags |= other.to_ulong();
+ }
} // namespace teachos::arch::context_switching::segment_descriptor_table
diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp
index e444a24..ad1366a 100644
--- a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp
+++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp
@@ -14,7 +14,13 @@ namespace teachos::arch::context_switching::segment_descriptor_table
return (std::bitset<4U>{_flags} & other) == other;
}
- auto gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; }
+ auto gdt_flags::get_limit() const -> std::bitset<4U>
+ {
+ return std::bitset<4U>{_limit_2};
+ }
- auto gdt_flags::operator|=(std::bitset<4U> other) -> void { _flags |= other.to_ulong(); }
+ auto gdt_flags::operator|=(std::bitset<4U> other) -> void
+ {
+ _flags |= other.to_ulong();
+ }
} // namespace teachos::arch::context_switching::segment_descriptor_table
diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp
index bbcee31..1c4729f 100644
--- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp
+++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp
@@ -12,8 +12,8 @@ namespace teachos::arch::context_switching::segment_descriptor_table
auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level)
-> segment_descriptor_base
{
- uint64_t constexpr BASE = 0x0;
- std::bitset<20U> constexpr LIMIT{0xFFFFF};
+ constexpr uint64_t BASE = 0x0;
+ constexpr std::bitset<20U> LIMIT{0xFFFFF};
gdt_flags flags{gdt_flags::GRANULARITY, LIMIT};
access_level |= access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT;
@@ -33,7 +33,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table
auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor_extension
{
- uint64_t constexpr TSS_LIMIT = sizeof(task_state_segment) - 1;
+ constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1;
access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL |
access_byte::TASK_STATE_SEGMENT_AVAILABLE};
gdt_flags const tss_gdt_flags{0U, TSS_LIMIT};
@@ -55,7 +55,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table
create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER);
// Task State Segment needs to be kept alive
- static auto tss = new task_state_segment();
+ auto static tss = new task_state_segment();
segment_descriptor_extension const tss_descriptor = create_tss_descriptor(tss);
global_descriptor_table global_descriptor_table{null_segment,
@@ -72,7 +72,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table
auto get_or_create_gdt() -> global_descriptor_table &
{
// Global Descriptor Table needs to be kept alive
- static global_descriptor_table gdt = create_gdt();
+ global_descriptor_table static gdt = create_gdt();
return gdt;
}
diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp
index 79088b8..79088b8 100644
--- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp
+++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp
diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp
index 04804d9..c3a03fc 100644
--- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp
+++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp
@@ -33,6 +33,9 @@ namespace teachos::arch::context_switching::segment_descriptor_table
: segment_descriptor_type::DATA_SEGMENT;
}
- segment_descriptor_base::operator uint64_t() const { return *reinterpret_cast<uint64_t const *>(this); }
+ segment_descriptor_base::operator uint64_t() const
+ {
+ return *reinterpret_cast<uint64_t const *>(this);
+ }
} // namespace teachos::arch::context_switching::segment_descriptor_table
diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp
index a28ec9b..5ea0d8a 100644
--- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp
+++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp
@@ -17,8 +17,14 @@ namespace teachos::arch::context_switching::segment_descriptor_table
// Nothing to do
}
- auto segment_descriptor_extension::get_first_gdt_entry() const -> segment_descriptor_base { return _base; }
+ auto segment_descriptor_extension::get_first_gdt_entry() const -> segment_descriptor_base
+ {
+ return _base;
+ }
- auto segment_descriptor_extension::get_second_gdt_entry() const -> uint64_t { return _base_3; }
+ auto segment_descriptor_extension::get_second_gdt_entry() const -> uint64_t
+ {
+ return _base_3;
+ }
} // namespace teachos::arch::context_switching::segment_descriptor_table
diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/pre/src/context_switching/syscall/main.cpp
index e291c10..b4ab468 100644
--- a/arch/x86_64/src/context_switching/syscall/main.cpp
+++ b/arch/x86_64/pre/src/context_switching/syscall/main.cpp
@@ -27,7 +27,7 @@ namespace teachos::arch::context_switching::syscall
asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5));
error error_code{};
- asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code));
+ asm volatile("mov %%al, %[output]" : [output] "=m"(error_code));
return {error_code, values};
}
diff --git a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp
index 3c43336..dbb3ed9 100644
--- a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp
+++ b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp
@@ -8,12 +8,12 @@ namespace teachos::arch::context_switching::syscall
{
namespace
{
- interrupt_descriptor_table::segment_selector constexpr KERNEL_CODE_SEGMENT_SELECTOR{
- 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL};
+ constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{
+ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL};
- auto constexpr IA32_STAR_ADDRESS = 0xC0000081;
- auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082;
- auto constexpr IA32_FMASK_ADDRESS = 0xC0000084;
+ constexpr auto IA32_STAR_ADDRESS = 0xC000'0081;
+ constexpr auto IA32_LSTAR_ADDRESS = 0xC000'0082;
+ constexpr auto IA32_FMASK_ADDRESS = 0xC000'0084;
} // namespace
diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp
index 84dbe5f..c120f77 100644
--- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp
+++ b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp
@@ -14,7 +14,7 @@ namespace teachos::arch::context_switching::syscall
{
auto write_to_vga_buffer(uint64_t buffer) -> response
{
- video::vga::text::write(reinterpret_cast<const char *>(buffer),
+ video::vga::text::write(reinterpret_cast<char const *>(buffer),
video::vga::text::common_attributes::green_on_black);
video::vga::text::newline();
return {error::OK};
@@ -22,11 +22,14 @@ namespace teachos::arch::context_switching::syscall
auto expand_user_heap() -> response
{
- static auto current_heap_end = memory::heap::USER_HEAP_START;
+ auto static current_heap_end = memory::heap::USER_HEAP_START;
uint64_t const heap_start = current_heap_end;
memory::remap_heap(heap_start, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE);
current_heap_end += memory::heap::USER_HEAP_SIZE;
- return {error::OK, {heap_start, memory::heap::USER_HEAP_SIZE}};
+ return {
+ error::OK,
+ {heap_start, memory::heap::USER_HEAP_SIZE}
+ };
}
} // namespace
@@ -62,7 +65,7 @@ namespace teachos::arch::context_switching::syscall
result = expand_user_heap();
break;
case type::ASSERT:
- teachos::arch::exception_handling::assert(arg_0, reinterpret_cast<const char *>(arg_1));
+ teachos::arch::exception_handling::assert(arg_0, reinterpret_cast<char const *>(arg_1));
break;
default:
teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number");
diff --git a/arch/x86_64/src/exception_handling/abort.cpp b/arch/x86_64/pre/src/exception_handling/abort.cpp
index e12e4cb..5dc6869 100644
--- a/arch/x86_64/src/exception_handling/abort.cpp
+++ b/arch/x86_64/pre/src/exception_handling/abort.cpp
@@ -11,5 +11,8 @@ namespace teachos::arch::exception_handling
* a matching implementation. Since the default implemenatation calls a number of functions the kernel does not
* currently implement, @p ::abort gets overridden to simply panic.
*/
- extern "C" auto abort() -> void { panic("Terminate was called, possibly due to an unhandled exception"); }
+ extern "C" auto abort() -> void
+ {
+ panic("Terminate was called, possibly due to an unhandled exception");
+ }
} // namespace teachos::arch::exception_handling
diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/pre/src/exception_handling/assert.cpp
index b2963de..b2963de 100644
--- a/arch/x86_64/src/exception_handling/assert.cpp
+++ b/arch/x86_64/pre/src/exception_handling/assert.cpp
diff --git a/arch/x86_64/src/exception_handling/panic.cpp b/arch/x86_64/pre/src/exception_handling/panic.cpp
index 8e3802a..9511a9a 100644
--- a/arch/x86_64/src/exception_handling/panic.cpp
+++ b/arch/x86_64/pre/src/exception_handling/panic.cpp
@@ -7,7 +7,10 @@ namespace teachos::arch::exception_handling
{
extern "C" char const message_prefix_panic[];
- auto panic(char const * reason) -> void { panic(message_prefix_panic, reason); }
+ auto panic(char const * reason) -> void
+ {
+ panic(message_prefix_panic, reason);
+ }
auto panic(char const * prefix, char const * reason) -> void
{
diff --git a/arch/x86_64/src/exception_handling/pure_virtual.cpp b/arch/x86_64/pre/src/exception_handling/pure_virtual.cpp
index 67772f7..67772f7 100644
--- a/arch/x86_64/src/exception_handling/pure_virtual.cpp
+++ b/arch/x86_64/pre/src/exception_handling/pure_virtual.cpp
diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp
index 9d061a8..9d061a8 100644
--- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp
+++ b/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp
diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/pre/src/kernel/cpu/call.cpp
index 98fa248..98fa248 100644
--- a/arch/x86_64/src/kernel/cpu/call.cpp
+++ b/arch/x86_64/pre/src/kernel/cpu/call.cpp
diff --git a/arch/x86_64/src/kernel/cpu/gdtr.cpp b/arch/x86_64/pre/src/kernel/cpu/gdtr.cpp
index 74a4e1c..74a4e1c 100644
--- a/arch/x86_64/src/kernel/cpu/gdtr.cpp
+++ b/arch/x86_64/pre/src/kernel/cpu/gdtr.cpp
diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/pre/src/kernel/cpu/idtr.cpp
index 7aa20c1..7aa20c1 100644
--- a/arch/x86_64/src/kernel/cpu/idtr.cpp
+++ b/arch/x86_64/pre/src/kernel/cpu/idtr.cpp
diff --git a/arch/x86_64/pre/src/kernel/cpu/if.cpp b/arch/x86_64/pre/src/kernel/cpu/if.cpp
new file mode 100644
index 0000000..5d056fc
--- /dev/null
+++ b/arch/x86_64/pre/src/kernel/cpu/if.cpp
@@ -0,0 +1,13 @@
+namespace teachos::arch::kernel::cpu
+{
+ auto set_interrupt_flag() -> void
+ {
+ asm volatile("sti");
+ }
+
+ auto clear_interrupt_flag() -> void
+ {
+ asm volatile("cli");
+ }
+
+} // namespace teachos::arch::kernel::cpu
diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/pre/src/kernel/cpu/msr.cpp
index 9c474a1..9d6a318 100644
--- a/arch/x86_64/src/kernel/cpu/msr.cpp
+++ b/arch/x86_64/pre/src/kernel/cpu/msr.cpp
@@ -4,7 +4,7 @@ namespace teachos::arch::kernel::cpu
{
namespace
{
- auto constexpr IA32_EFER_ADDRESS = 0xC0000080;
+ constexpr auto IA32_EFER_ADDRESS = 0xC000'0080;
}
auto read_msr(uint32_t msr) -> uint64_t
diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/pre/src/kernel/cpu/segment_register.cpp
index b08c9c4..b08c9c4 100644
--- a/arch/x86_64/src/kernel/cpu/segment_register.cpp
+++ b/arch/x86_64/pre/src/kernel/cpu/segment_register.cpp
diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/pre/src/kernel/cpu/tr.cpp
index a435540..a435540 100644
--- a/arch/x86_64/src/kernel/cpu/tr.cpp
+++ b/arch/x86_64/pre/src/kernel/cpu/tr.cpp
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/pre/src/kernel/main.cpp
index 43b5f90..43b5f90 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/pre/src/kernel/main.cpp
diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp
index 525f45c..525f45c 100644
--- a/arch/x86_64/src/memory/heap/bump_allocator.cpp
+++ b/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp
diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp
index 35cd623..709cda1 100644
--- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp
+++ b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp
@@ -27,13 +27,25 @@ namespace teachos::arch::memory::heap
heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr;
user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr;
- auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); }
+ auto global_heap_allocator::kmalloc(std::size_t size) -> void *
+ {
+ return kernel().allocate(size);
+ }
- auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); }
+ auto global_heap_allocator::kfree(void * pointer) noexcept -> void
+ {
+ kernel().deallocate(pointer);
+ }
- auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); }
+ auto global_heap_allocator::malloc(std::size_t size) -> void *
+ {
+ return user().allocate(size);
+ }
- auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); }
+ auto global_heap_allocator::free(void * pointer) noexcept -> void
+ {
+ user().deallocate(pointer);
+ }
auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void
{
@@ -45,20 +57,21 @@ namespace teachos::arch::memory::heap
case heap_allocator_type::NONE:
// Nothing to do
break;
- case heap_allocator_type::BUMP: {
- static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE};
+ case heap_allocator_type::BUMP:
+ {
+ bump_allocator static kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE};
kernel_allocator_instance = &kernel_allocator;
break;
}
- case heap_allocator_type::LINKED_LIST: {
- static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE};
+ case heap_allocator_type::LINKED_LIST:
+ {
+ linked_list_allocator static kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE};
kernel_allocator_instance = &kernel_allocator;
break;
}
}
- [[gnu::section(".user_data")]]
- static user_heap_allocator user_allocator{};
+ [[gnu::section(".user_data")]] user_heap_allocator static user_allocator{};
user_allocator_instance = &user_allocator;
}
diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp
index 63a6111..00ca366 100644
--- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp
+++ b/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp
@@ -9,7 +9,7 @@ namespace teachos::arch::memory::heap
{
linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end)
: first(nullptr)
- , mutex{stl::mutex{}}
+ , mutex{kstd::mutex{}}
{
auto const heap_size = heap_end - heap_start;
exception_handling::assert(
diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/pre/src/memory/heap/memory_block.cpp
index bc97bd6..4c07454 100644
--- a/arch/x86_64/src/memory/heap/memory_block.cpp
+++ b/arch/x86_64/pre/src/memory/heap/memory_block.cpp
@@ -11,5 +11,8 @@ namespace teachos::arch::memory::heap
this->next = next;
}
- memory_block::~memory_block() { memset(static_cast<void *>(this), 0U, sizeof(memory_block)); }
+ memory_block::~memory_block()
+ {
+ memset(static_cast<void *>(this), 0U, sizeof(memory_block));
+ }
} // namespace teachos::arch::memory::heap
diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp
index 427a68a..96de005 100644
--- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
+++ b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp
@@ -39,7 +39,7 @@ namespace teachos::arch::memory::heap
}
}
- char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory";
+ constexpr char OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory";
context_switching::syscall::syscall(context_switching::syscall::type::ASSERT,
{false, reinterpret_cast<uint64_t>(&OUT_OF_MEMORY_ERROR_MESSAGE)});
return nullptr;
@@ -178,7 +178,7 @@ namespace teachos::arch::memory::heap
// Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean
// that the block has already been deallocated and we therefore attempted a double free.
- char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected";
+ constexpr char DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected";
context_switching::syscall::syscall(
context_switching::syscall::type::ASSERT,
{previous_block == nullptr ||
diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/pre/src/user/main.cpp
index 8b07e4a..8b07e4a 100644
--- a/arch/x86_64/src/user/main.cpp
+++ b/arch/x86_64/pre/src/user/main.cpp
diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld
index 3d9a7ae..064b8d7 100644
--- a/arch/x86_64/scripts/kernel.ld
+++ b/arch/x86_64/scripts/kernel.ld
@@ -3,7 +3,8 @@ ENTRY(_start)
/*****************************************************************************
* Virtual and linear start addresses of the TeachOS kernel
*****************************************************************************/
-TEACHOS_LOW = 1M;
+TEACHOS_PMA = 1M;
+TEACHOS_VMA = 0xFFFFFFFF80000000;
PHDRS {
boot_rodata PT_LOAD FLAGS(4);
@@ -22,15 +23,16 @@ SECTIONS
* 32-Bit mode, so we want to live down low, but we need to leave the 1MiB
* hole open since some BIOS functionality resides below it.
***************************************************************************/
- . = TEACHOS_LOW;
+ . = TEACHOS_PMA;
/***************************************************************************
- * We want to be able to be able to access all memory (linear and virtual)
+ * We want to be able to be able to access all memory (physical and virtual)
* during bootstrapping and operation. To achieve this, we define some
* symbols at the beginning.
***************************************************************************/
- _start_linear = .;
- _start_virtual = .;
+ _start_physical = .;
+ _start_virtual = . + TEACHOS_VMA;
+
/***************************************************************************
* The bootstrapping infratructure goes first. We first place the read-only
@@ -63,78 +65,59 @@ SECTIONS
* Now it is time to load the 64-bit kernel code. We
* make sure to align the loaded data onto a page boundary.
***************************************************************************/
- .init ALIGN(4K) : AT(ADDR (.init))
- {
- /*
- * Make sure that the crt code is wrapped around the compiler generated
- * initialization code.
- */
- KEEP(*crti.s.o*(.init))
- KEEP(*(EXCLUDE_FILE (*crti.s.o* *crtn.s.o*) .init))
- KEEP(*crtn.s.o*(.init))
- } :text
-
- .fini ALIGN(4K) : AT(ADDR (.fini))
- {
- /*
- * Make sure that the crt code is wrapped around the compiler generated
- * finalizer code.
- */
- KEEP(*crti.s.o*(.fini))
- KEEP(*(EXCLUDE_FILE (*crti.s.o* *crtn.s.o*) .fini))
- KEEP(*crtn.s.o*(.fini))
- }
+ . = ALIGN(4K);
+ . += TEACHOS_VMA;
- .stl_text ALIGN(4K) : AT(ADDR (.stl_text))
+ .stl_text ALIGN(4K) : AT(ADDR (.stl_text) - TEACHOS_VMA)
{
*(.stl_text .stl_text*)
KEEP(*libstdc++.a:*(.text .text.*))
- }
+ } :text
- .text ALIGN(4K) : AT(ADDR (.text))
+ .text ALIGN(4K) : AT(ADDR (.text) - TEACHOS_VMA)
{
*(.text .text.*)
}
- .user_text ALIGN(4K) : AT(ADDR (.user_text))
+ .user_text ALIGN(4K) : AT(ADDR (.user_text) - TEACHOS_VMA)
{
*(.user_text .user_text.*)
}
- .rodata ALIGN(4K) : AT (ADDR (.rodata))
+ .rodata ALIGN(4K) : AT (ADDR (.rodata) - TEACHOS_VMA)
{
*(.rodata)
*(.rodata.*)
} :rodata
- .ctors ALIGN(4K) : AT (ADDR (.ctors))
+ .ctors ALIGN(4K) : AT (ADDR (.ctors) - TEACHOS_VMA)
{
- KEEP(*crtbegin.o(.ctors))
- KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors))
+ __ctors_start = .;
KEEP(*(SORT(.ctors.*)))
- KEEP(*crtend.o(.ctors))
+ KEEP(*(.ctors))
+ __ctors_end = .;
} :data
- .dtors ALIGN(4K) : AT (ADDR (.dtors))
+ .init_array ALIGN(4K) : AT (ADDR (.init_array) - TEACHOS_VMA)
{
- KEEP(*crtbegin.o(.dtors))
- KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors))
- KEEP(*(SORT(.dtors.*)))
- KEEP(*crtend.o(.dtors))
+ __init_array_start = .;
+ KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)))
+ KEEP(*(.init_array))
+ __init_array_end = .;
}
- .bss ALIGN(4K) : AT (ADDR (.bss))
+ .bss ALIGN(4K) : AT (ADDR (.bss) - TEACHOS_VMA)
{
*(COMMON)
*(.bss*)
}
- .data ALIGN(4K) : AT (ADDR (.data))
+ .data ALIGN(4K) : AT (ADDR (.data) - TEACHOS_VMA)
{
*(.data*)
}
- .user_data ALIGN(4K) : AT (ADDR (.user_data))
+ .user_data ALIGN(4K) : AT (ADDR (.user_data) - TEACHOS_VMA)
{
*(.user_data .user_data.*)
}
@@ -143,8 +126,8 @@ SECTIONS
* In accordance with the symbol definitions at the start, we generate some
* symbols to mark the end of our loaded image.
***************************************************************************/
- _end_virtual = ADDR(.bss) + SIZEOF(.bss);
- _end_linear = _end_virtual;
+ _end_virtual = .;
+ _end_physical = _end_virtual - TEACHOS_VMA;
/DISCARD/ : { *(.comment) }
}
diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s
deleted file mode 100644
index 7932045..0000000
--- a/arch/x86_64/src/boot/boot.s
+++ /dev/null
@@ -1,368 +0,0 @@
-.extern _end_physical
-.extern _init
-.extern kernel_main
-
-
-/**
- * Uninitialized data for the bootstrapping process.
- */
-.section .boot_bss, "aw", @nobits
-
-/**
- * Reserve some space for the Multiboot 2 information pointer.
- */
-.global multiboot_information_pointer
-multiboot_information_pointer: .skip 4
-
-/**
- * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging.
- */
-.align 4096
-
-/**
- * Reserve space for the page maps we are going to use during startup.
- *
- * Note: We are going to use large pages to make the initial mapping code
- * simpler.
- *
- * We need:
- * - A single PML 4 (since we will only use 4-level paging)
- * - 1 PML 3
- * - 1 PML 2
- */
-
-.global page_map_level_4
-page_map_level_4: .skip 512 * 8
-
-.global page_map_level_3
-page_map_level_3: .skip 512 * 8
-
-.global page_map_level_2
-page_map_level_2: .skip 512 * 8
-
-/**
- * Stack space for the bootstrapping process.
- *
- * Note: We are going to reserve 1 MiB for now. If/when the kernel requires
- * more space to run, it will have to relocate the stack.
- */
-.section .boot_stack, "aw", @nobits
-.align 16
-
-stack_bottom: .skip 1 << 20
-stack_top:
-
-/**
- * Constants for the bootstrapping process.
- */
-.section .boot_rodata, "a", @progbits
-
-/**
- * A valid Global Descriptor Table is still required in long mode. However, we
- * only need a single entry for the "code segment", so we will setup a single
- * segment table below.
- *
- * Bit 43: "E" in the access byte => mark the segment as executable.
- * Bit 44: "S" in the access byte => mark the segment as code or data.
- * Bit 47: "P" in the access byte => mark the segment as being present.
- * Bit 53: "L" in the flags byte => mark the segment as being for long mode
- */
-
-global_descriptor_table: .quad 0
-global_descriptor_table_code = . - global_descriptor_table
-.quad (1<<43) | (1<<44) | (1<<47) | (1<<53)
-
-/**
- * We also need a pointer that we can load into the GDTR.
- *
- * The pointer consists of a word describing the size of the table minus 1 and
- * the pointer to the actual table.
- */
-global_descriptor_table_pointer:
-.word . - global_descriptor_table - 1
-.quad global_descriptor_table
-
-/**
- * We are going to print some messages in case we panic during boot, so we are
- * going to store them here as well
- */
-.global message_prefix_panic
-message_prefix_panic:
-.string "TeachOS Panic: "
-message_not_loaded_by_multiboot2:
-.string "The operating system was not loaded by a Multiboot 2 loader."
-message_cpuid_instruction_no_supported:
-.string "The 'cpuid' instruction is not supported on this platform."
-mesage_long_mode_not_supported:
-.string "Long mode is not supported by this platform."
-
-/**
- * Mutable data for the bootstrapping process.
- */
-.section .boot_data, "aw", @progbits
-
-/**
- * We need a pointer to our current position in the VGA text buffer.
- */
-.global vga_buffer_pointer
-vga_buffer_pointer: .long 0xb8000
-
-/**
- * Code for the bootstrapping process.
- */
-.section .boot_text, "ax", @progbits
-.align 16
-.code32
-
-.global halt
-halt:
-1:
- hlt
- jmp 1b
-
-/**
- * Print a given panic message and then halt the machine.
- *
- * Parameters:
- * - [stack - 0] message: the message to print
- */
-_panic:
- push %ebp
- mov %esp, %ebp
-
- push message_prefix_panic
- push $0x4f
- call _print
- add $8, %esp
-
- push 8(%ebp)
- push 0x4f
- call _print
- add $8, %esp
-
- call halt
-
-/**
- * Print a message via the VGA buffer.
- *
- * Parameters:
- * - [stack - 4] message: the message to print
- * - [stack - 0] color: the color of the message
- */
-_print:
- push %ebp
- mov %esp, %ebp
-
- push %ebx
- push %esi
- mov 8(%ebp), %eax
- mov 12(%ebp), %ebx
- mov $0, %ecx
- mov (vga_buffer_pointer), %esi
-
-.Lprint_loop:
- mov (%ebx, %ecx), %dl
- test %dl, %dl
- je .Lupdate_vga_buffer_address
- mov %dl, (%esi, %ecx, 2)
- mov %al, 1(%esi, %ecx, 2)
- inc %ecx
- jmp .Lprint_loop
-
-.Lupdate_vga_buffer_address:
- shl $1, %ecx
- add %ecx, (vga_buffer_pointer)
-
-.Lprint_end:
- pop %esi
- pop %ebx
- mov %ebp, %esp
- pop %ebp
- ret
-
-/**
- * This is our entry point after being loaded by the bootloader.
- *
- * Having this in assembly makes it easier for us to keep things together.
- */
-.global _start
-_start:
- mov $stack_top, %esp
- mov %esp, %ebp
-
- call assert_loaded_by_multiboot2_loader
- call assert_cpuid_instruction_is_supported
- call assert_cpu_supports_long_mode
- call prepare_page_maps
- call enable_paging
- call enable_sse
-
- lgdt (global_descriptor_table_pointer)
- jmp $global_descriptor_table_code, $_transition_to_long_mode
-
- call halt
-
-/**
- * Assert that the CPU supports going into long mode.
- */
-assert_cpu_supports_long_mode:
- mov $0x80000000, %eax
- cpuid
- cmp $0x80000001, %eax
- jb .Llong_mode_assertion_failed
-
- mov $0x80000001, %eax
- cpuid
- test $(1 << 29), %edx
- jz .Llong_mode_assertion_failed
- ret
-.Llong_mode_assertion_failed:
- push $mesage_long_mode_not_supported
- call _panic
-
-/**
- * Assert that the CPU supports the CPUID instruction.
- *
- * The primary way to check for support of the instruction is to flip the ID
- * bin in EFLAGS and then check if this changed was accepted. If so, the CPU
- * supports the CPUID instruction, otherwise it most-likely doesn't.
- */
-assert_cpuid_instruction_is_supported:
- pushfl
- pop %eax
- mov %eax, %ecx
-
- xor $(1 << 21), %eax /* Flip the ID bit */
- push %eax /* Move the new bitset on the stack for loading */
- popfl /* Load the flags with ID set back into EFLAGS */
- pushfl /* Copy the flags back onto the stack */
- pop %eax /* Load the flags for further checking */
-
- push %ecx
- popfl
-
- cmp %ecx, %eax
- je .Lcpuid_assertion_fail
- ret
-.Lcpuid_assertion_fail:
- push $message_cpuid_instruction_no_supported
- call _panic
-
-/**
- * Assert that we were loaded by a Multiboot 2 compliant bootloader.
- *
- * This assertion will panic the system if the magic signature was not found.
- * If we were loaded my an appropriate bootloader, this function also saves
- * the provided MBI pointer to `multiboot_information_pointer`.
- */
-assert_loaded_by_multiboot2_loader:
- cmp $0x36d76289, %eax /* Check if we received the
- expected magic */
- jne .Lmultiboot2_assertion_fail /* Panic otherwise */
- mov %ebx, multiboot_information_pointer /* Store the MBI pointer */
- ret
-.Lmultiboot2_assertion_fail:
- push $message_not_loaded_by_multiboot2
- call _panic
-
-/**
- * Enable paging.
- *
- * Note: This routine expects for there to be a valid set of page maps already
- * set up for use.
- */
-enable_paging:
- mov $page_map_level_4, %eax
- mov %eax, %cr3
-
- /* Enable Physical Address Extension */
- mov %cr4, %eax
- or $(1 << 5), %eax
- mov %eax, %cr4
-
- /* Enable long mode support */
- mov $0xC0000080, %ecx
- rdmsr
- or $(1 << 8), %eax
- wrmsr
-
- /* Enable paging */
- mov %cr0, %eax
- or $(1 << 31), %eax
- mov %eax, %cr0
-
- ret
-
-/**
- * Enable use of SSE instructions.
- */
-enable_sse:
- mov %cr0, %eax
- and $0xfffffffb, %eax
- or $0x00000002, %eax
- mov %eax, %cr0
-
- mov %cr4, %eax
- or $(3 << 9), %eax
- mov %eax, %cr4
-
- ret
-
-/**
- * Prepare the page maps.
- *
- * We map all physical memory we were loaded in plus one additional page. The
- * mapping is done in terms of huge pages (2 MiB per page) to save on required
- * page map entries.
- */
-prepare_page_maps:
- /* Map the P4 table recursively */
- mov $page_map_level_4, %eax
- or $0b11, %eax /* Write present + writable flags into eax register */
- mov %eax, (page_map_level_4 + 511 * 8)
-
- /* Add an entry to the PML4, pointing to the PML3 */
- mov $page_map_level_3, %eax
- or $0x3, %eax
- mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8)
-
- /* Add an entry to the PML3, pointing to the PML2 */
- mov $page_map_level_2, %eax
- or $0x3, %eax
- mov %eax, (page_map_level_3 + ((0x0000000000100000 >> 30) & 0x1ff) * 8)
-
- xor %ecx, %ecx
-
- mov $_end_linear, %esi
- shr $21, %esi
- add $2, %esi
-
-.Lmap_pages:
- mov $(1 << 21), %eax
- mul %ecx
- or $((1 << 0) | (1 << 1) | (1 << 7)), %eax
- mov %eax, page_map_level_2(,%ecx,8)
-
- inc %ecx
- cmp %esi, %ecx
- jne .Lmap_pages
-
- ret
-
-.section .boot_text, "ax", @progbits
-.code64
-
-_transition_to_long_mode:
- xor %rax, %rax
- mov %rax, %ss
- mov %rax, %ds
- mov %rax, %es
- mov %rax, %fs
- mov %rax, %gs
-
- movl $0xb8000, (vga_buffer_pointer)
-
- call _init
-
- call kernel_main
- call halt
diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S
new file mode 100644
index 0000000..79b3ec7
--- /dev/null
+++ b/arch/x86_64/src/boot/boot32.S
@@ -0,0 +1,449 @@
+#include "x86_64/boot/boot.hpp"
+
+/**
+ * @brief Uninitialized data for the bootstrapping process.
+ */
+.section .boot_bss, "aw", @nobits
+
+/**
+ * @brief Storage for the multiboot2 information pointer.
+ */
+.global multiboot_information_pointer
+multiboot_information_pointer: .skip 8
+
+.align 4096
+
+page_maps_start:
+page_map_level_4: .skip 512 * 8
+page_map_level_3_high: .skip 512 * 8
+page_map_level_3_low: .skip 512 * 8
+page_map_level_2: .skip 512 * 8
+page_maps_end = .
+page_maps_size = page_maps_end - page_maps_start
+
+/**
+ * @brief Storage for the bootstrap stack.
+ */
+.section .boot_stack, "aw", @nobits
+.align 16
+
+early_stack_bottom: .skip 1 << 8
+early_stack_top:
+early_stack_size = early_stack_top - early_stack_bottom
+
+/**
+ * @brief Constants for the bootstrapping process.
+ */
+.section .boot_rodata, "a", @progbits
+
+.global global_descriptor_table_data
+
+/**
+ * @brief A basic GDT for long mode.
+ */
+global_descriptor_table:
+global_descriptor_table_null = . - global_descriptor_table
+.quad 0
+global_descriptor_table_code = . - global_descriptor_table
+.quad GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE | (1 << 55)
+global_descriptor_table_data = . - global_descriptor_table
+.quad GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | (1 << 54) | (1 << 55)
+global_descriptor_table_end:
+
+message_prefix_panic: .string "Panic: "
+message_not_loaded_by_multiboot2: .string "The operating system was not loaded by a Multiboot 2 loader."
+message_cpuid_instruction_no_supported: .string "The 'cpuid' instruction is not supported on this platform."
+message_long_mode_not_supported: .string "Long mode is not supported by this platform."
+message_return_from_kernel_main: .string "Execution returned from kernel main."
+
+/**
+ * @brief Initialized data for the bootstrapping process.
+ */
+.section .boot_data, "aw", @progbits
+
+/**
+ * @brief A pointer to the current position within the VGA text buffer.
+ */
+.global vga_buffer_pointer
+vga_buffer_pointer: .quad 0xb8000
+
+/**
+ * @brief Code for the bootstrapping process.
+ */
+.section .boot_text, "ax", @progbits
+.align 16
+.code32
+
+.macro pie_base
+ push %esi
+ call 0f
+ 0:
+ pop %esi
+.endm
+
+.macro function_start
+ push %ebp
+ mov %esp, %ebp
+.endm
+
+.macro function_end
+ leave
+ ret
+.endm
+
+.macro pie_function_start
+ function_start
+ pie_base
+.endm
+
+.macro pie_function_end
+ pop %esi
+ function_end
+.endm
+
+/**
+ * @brief Prepare the environment and start the kernel.
+ *
+ * This function performs all necessary checks to ensure the system was loaded
+ * by the expected loader and supports all features required to run the kernel.
+ * If successful, it prepares the system by setting up memory virtualization
+ * and then start the kernel proper.
+ *
+ * @param %eax The Multiboot 2 magic marker.
+ * @param %ebx The Multiboot 2 information pointer.
+ * @return void This function does not return.
+ */
+.global _start
+_start:
+ call 0f
+0:
+ pop %esi
+
+ lea (early_stack_top - 0b)(%esi), %ecx
+
+ mov %ecx, %esp
+ mov %esp, %ebp
+
+ call _assert_loaded_by_multiboot2_loader
+ call _save_multiboot_information_pointer
+
+ call _assert_cpuid_instruction_is_supported
+ call _assert_cpu_supports_long_mode
+
+ push $HUGE_PAGES_TO_MAP
+ call _prepare_page_maps
+ add $4, %esp
+
+ call _enable_paging
+ call _enable_sse
+ call _reload_gdt
+
+ lea (_entry64 - 0b)(%esi), %eax
+ pushl $global_descriptor_table_code
+ pushl %eax
+ lret
+
+/**
+ * @brief Halt the system.
+ *
+ * This function will instruct the CPU to halt. It will try to keep the CPU
+ * halted, even if interrupts occur.
+ *
+ * @return This function never returns.
+ */
+_halt:
+ function_start
+
+1:
+ hlt
+ jmp 1b
+
+ function_end
+
+/**
+ * @brief Print a message via the VGA text buffer.
+ *
+ * @param ebp+12 The message to print.
+ * @param ebp+8 The color to print the message in.
+ */
+_print:
+ pie_function_start
+
+ push %edi
+ push %ebx
+
+ mov 8(%ebp), %al
+ mov 12(%ebp), %edx
+ mov $0, %ecx
+ lea (vga_buffer_pointer - 0b)(%esi), %edi
+ mov (%edi), %edi
+
+1:
+ mov (%edx, %ecx), %bl
+ test %bl, %bl
+ je 2f
+ mov %bl, (%edi, %ecx, 2)
+ mov %al, 1(%edi, %ecx, 2)
+ inc %ecx
+ jmp 1b
+
+2:
+ shl $1, %ecx
+ add %ecx, %edi
+ lea (vga_buffer_pointer - 0b)(%esi), %ecx
+ mov %edi, (%ecx)
+
+ pop %ebx
+ pop %edi
+
+ pie_function_end
+
+/**
+ * @brief Print a given panic message and then halt the machine as if by calling ::halt()
+ *
+ * @param ebp+4 A message to print.
+ * @return This function does not return.
+ */
+_panic:
+ pie_function_start
+
+ lea (message_prefix_panic - 0b)(%esi), %eax
+
+ push %eax
+ push $0x4f
+ call _print
+
+ mov 16(%ebp), %eax
+ mov %eax, 8(%ebp)
+ call _print
+ add $8, %esp
+
+ call _halt
+
+ pie_function_end
+
+/**
+ * Assert that we were loaded by a Multiboot 2 compliant bootloader.
+ *
+ * This assertion will panic the system if the magic signature was not found.
+ * If we were loaded my an appropriate bootloader, this function also saves
+ * the provided MBI pointer to `multiboot_information_pointer`.
+ */
+_assert_loaded_by_multiboot2_loader:
+ pie_function_start
+
+ cmp $MULTIBOOT2_MAGIC, %eax
+ je 1f
+ lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax
+ push %eax
+ call _panic
+1:
+ pie_function_end
+
+/**
+ * @brief Store the multiboot 2 information pointer in the global memory.
+ *
+ * @return void
+ */
+_save_multiboot_information_pointer:
+ pie_function_start
+
+ lea (multiboot_information_pointer - 0b)(%esi), %eax
+ mov %ebx, (%eax)
+
+ pie_function_end
+
+/**
+ * @brief Assert that the CPU supports the CPUID instruction.
+ *
+ * The primary way to check for support of the instruction is to flip the ID
+ * bin in EFLAGS and then check if this changed was accepted. If so, the CPU
+ * supports the CPUID instruction, otherwise it most-likely doesn't.
+ */
+_assert_cpuid_instruction_is_supported:
+ pie_function_start
+
+ pushfl
+ pop %eax
+ mov %eax, %ecx
+
+ xor $(1 << 21), %eax /* Flip the ID bit */
+ push %eax /* Move the new bitset on the stack for loading */
+ popfl /* Load the flags with ID set back into EFLAGS */
+ pushfl /* Copy the flags back onto the stack */
+ pop %eax /* Load the flags for further checking */
+
+ push %ecx
+ popfl
+
+ cmp %ecx, %eax
+ jne 1f
+ lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax
+ push %eax
+ call _panic
+
+1:
+ pie_function_end
+
+/**
+ * @brief Assert that the CPU supports going into long mode.
+ */
+_assert_cpu_supports_long_mode:
+ pie_function_start
+
+ mov $0x80000000, %eax
+ cpuid
+ cmp $0x80000001, %eax
+ jb 1f
+
+ mov $0x80000001, %eax
+ cpuid
+ test $(1 << 29), %edx
+ jnz 2f
+1:
+ lea (message_long_mode_not_supported - 0b)(%esi), %eax
+ push %eax
+ call _panic
+2:
+ pie_function_end
+
+/**
+ * @brief Prepare a recursive page map hierarchy
+ *
+ * @param ebp+8 The number of huge pages to map
+ * @return void
+ */
+_prepare_page_maps:
+ pie_function_start
+
+ push %edi
+
+ call _clear_page_map_memory
+
+ lea (page_map_level_4 - 0b)(%esi), %edi
+ mov %edi, %eax
+ or $0b11, %eax
+ mov %eax, (510 * 8)(%edi)
+
+ lea (page_map_level_3_low - 0b)(%esi), %eax
+ or $0b11, %eax
+ mov %eax, (%edi)
+
+ lea (page_map_level_3_high - 0b)(%esi), %eax
+ or $0b11, %eax
+ mov %eax, (511 * 8)(%edi)
+
+ lea (page_map_level_3_low - 0b)(%esi), %edi
+ lea (page_map_level_2 - 0b)(%esi), %eax
+ or $0b11, %eax
+ mov %eax, (%edi)
+
+ lea (page_map_level_3_high - 0b)(%esi), %edi
+ lea (page_map_level_2 - 0b)(%esi), %eax
+ or $0b11, %eax
+ mov %eax, (510 * 8)(%edi)
+
+ lea (page_map_level_2 - 0b)(%esi), %edi
+ mov 8(%ebp), %ecx
+
+1:
+ dec %ecx
+ mov $(1 << 21), %eax
+ mul %ecx
+ or $0b10000011, %eax
+ mov %eax, (%edi, %ecx, 8)
+
+ test %ecx, %ecx
+ jnz 1b
+
+ pop %edi
+
+ pie_function_end
+
+/**
+ * @brief Clear all page map memory by filling it with 0s.
+ *
+ * @return void
+ */
+_clear_page_map_memory:
+ pie_function_start
+
+ push %edi
+
+ xor %eax, %eax
+ mov $page_maps_size, %ecx
+ shr $2, %ecx
+ lea (page_maps_start - 0b)(%esi), %edi
+ rep stosl
+
+ pop %edi
+
+ pie_function_end
+
+/**
+ * @p Enable memory virtualization via paging.
+ *
+ * Note: This routine expects for there to be a valid set of page maps already
+ * set up for use.
+ *
+ * @return void
+ */
+_enable_paging:
+ pie_function_start
+
+ lea (page_map_level_4 - 0b)(%esi), %eax
+ mov %eax, %cr3
+
+ /* Enable Physical Address Extension */
+ mov %cr4, %eax
+ or $(1 << 5), %eax
+ mov %eax, %cr4
+
+ /* Enable long mode support */
+ mov $0xC0000080, %ecx
+ rdmsr
+ or $(1 << 8), %eax
+ wrmsr
+
+ /* Enable paging */
+ mov %cr0, %eax
+ or $(1 << 31), %eax
+ mov %eax, %cr0
+
+ pie_function_end
+
+/**
+ * @brief Enable use of SSE instructions.
+ */
+_enable_sse:
+ function_start
+
+ mov %cr0, %eax
+ and $0xfffffffb, %eax
+ or $0x00000002, %eax
+ mov %eax, %cr0
+
+ mov %cr4, %eax
+ or $(3 << 9), %eax
+ mov %eax, %cr4
+
+ function_end
+
+/**
+ * @brief Prepare a new GTD and load make it active.
+ *
+ * @return void
+ */
+_reload_gdt:
+ pie_function_start
+
+ sub $10, %esp
+ lea (global_descriptor_table - 0b)(%esi), %eax
+ movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp)
+ mov %eax, 2(%esp)
+ movl $0, 6(%esp)
+
+ lgdt (%esp)
+ add $10, %esp
+
+ pie_function_end
diff --git a/arch/x86_64/src/boot/crti.s b/arch/x86_64/src/boot/crti.s
deleted file mode 100644
index 26878fe..0000000
--- a/arch/x86_64/src/boot/crti.s
+++ /dev/null
@@ -1,13 +0,0 @@
-.code64
-
-.section .init
-.global _init
-_init:
- push %rbp
- movq %rsp, %rbp
-
-.section .fini
-.global _fini
-_fini:
- push %rbp
- movq %rsp, %rbp
diff --git a/arch/x86_64/src/boot/crtn.s b/arch/x86_64/src/boot/crtn.s
deleted file mode 100644
index 06fb7ce..0000000
--- a/arch/x86_64/src/boot/crtn.s
+++ /dev/null
@@ -1,9 +0,0 @@
-.code64
-
-.section .init
- popq %rbp
- ret
-
-.section .fini
- popq %rbp
- ret
diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s
new file mode 100644
index 0000000..657b0a8
--- /dev/null
+++ b/arch/x86_64/src/boot/entry64.s
@@ -0,0 +1,60 @@
+.section .bss, "aw", @nobits
+
+//! A structure containing information gathered during the bootstrap process.
+//! Expected layout (as described by teachos::boot::information):
+//!
+//! struct
+//! {
+//! multiboot2::information_view const * mbi;
+//! std::size_t vga_buffer_index;
+//! }
+.global bootstrap_information
+bootstrap_information: .skip 16
+
+.align 16
+.global stack_top
+stack_bottom: .skip 1 << 20
+stack_top:
+stack_size = stack_top - stack_bottom
+
+.section .boot_text, "ax", @progbits
+.code64
+
+.global _entry64
+_entry64:
+ mov $global_descriptor_table_data, %rax
+ mov %rax, %ss
+ mov %rax, %ds
+ mov %rax, %es
+ mov %rax, %fs
+ mov %rax, %gs
+
+ mov $stack_top, %rsp
+ mov %rsp, %rbp
+
+ mov multiboot_information_pointer, %rax
+ or $TEACHOS_VMA, %rax
+ mov vga_buffer_pointer, %rdx
+ sub $0xb8000, %rdx
+ mov %rax, (bootstrap_information)
+ mov %rdx, (bootstrap_information + 8)
+
+ call invoke_global_constructors
+
+ xor %rax, %rax
+ mov %rax, %rbp
+ mov %rax, %rdx
+ mov %rax, %rsi
+
+ mov $stack_size, %rcx
+ shr $3, %rcx
+ lea (stack_bottom), %rdi
+ rep stosq
+
+ mov %rax, %rdi
+
+ call main
+
+1:
+ hlt
+ jmp 1b
diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp
new file mode 100644
index 0000000..46dd5e4
--- /dev/null
+++ b/arch/x86_64/src/boot/initialize_runtime.cpp
@@ -0,0 +1,26 @@
+#include <algorithm>
+#include <functional>
+#include <span>
+
+extern "C"
+{
+ using global_initializer = auto (*)() -> void;
+
+ extern global_initializer __ctors_start;
+ extern global_initializer __ctors_end;
+ extern global_initializer __init_array_start;
+ extern global_initializer __init_array_end;
+
+ auto invoke_global_constructors() -> void
+ {
+ auto constructors = std::span{&__ctors_start, &__ctors_end};
+ auto initializers = std::span{&__init_array_start, &__init_array_end};
+
+ auto apply_invoke = [](auto invokable) -> void {
+ std::invoke(invokable);
+ };
+
+ std::ranges::for_each(constructors, apply_invoke);
+ std::ranges::for_each(initializers, apply_invoke);
+ }
+}
diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp
new file mode 100644
index 0000000..ade02aa
--- /dev/null
+++ b/arch/x86_64/src/kapi/cio.cpp
@@ -0,0 +1,20 @@
+#include "kapi/cio.hpp"
+
+#include "x86_64/vga/text.hpp"
+
+#include <optional>
+
+namespace teachos::cio
+{
+
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ auto static constinit vga_device = std::optional<vga::x86_64::text::device>{};
+
+ auto init() -> void
+ {
+ vga_device.emplace();
+ vga_device->cursor(false);
+ set_output_device(*vga_device);
+ }
+
+} // namespace teachos::cio
diff --git a/arch/x86_64/src/kapi/cpu.cpp b/arch/x86_64/src/kapi/cpu.cpp
new file mode 100644
index 0000000..22543ee
--- /dev/null
+++ b/arch/x86_64/src/kapi/cpu.cpp
@@ -0,0 +1,12 @@
+#include "kapi/cpu.hpp"
+
+namespace teachos::cpu
+{
+
+ auto halt() -> void
+ {
+ asm volatile("1: hlt\njmp 1b");
+ __builtin_unreachable();
+ }
+
+} // namespace teachos::cpu
diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp
new file mode 100644
index 0000000..8c53c4c
--- /dev/null
+++ b/arch/x86_64/src/kapi/memory.cpp
@@ -0,0 +1,193 @@
+#include "kapi/memory.hpp"
+
+#include "kapi/boot.hpp"
+#include "kapi/cio.hpp"
+#include "kapi/system.hpp"
+
+#include "x86_64/boot/boot.hpp"
+#include "x86_64/boot/ld.hpp"
+#include "x86_64/cpu/registers.hpp"
+#include "x86_64/memory/buffered_allocator.hpp"
+#include "x86_64/memory/kernel_mapper.hpp"
+#include "x86_64/memory/mmu.hpp"
+#include "x86_64/memory/page_table.hpp"
+#include "x86_64/memory/page_utilities.hpp"
+#include "x86_64/memory/paging_root.hpp"
+#include "x86_64/memory/recursive_page_mapper.hpp"
+#include "x86_64/memory/region_allocator.hpp"
+#include "x86_64/memory/scoped_mapping.hpp"
+
+#include <multiboot2/information.hpp>
+
+#include <atomic>
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <span>
+#include <utility>
+
+namespace teachos::memory
+{
+
+ namespace
+ {
+ constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz};
+ constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2;
+
+ //! Instantiate a basic, memory region based, early frame allocator for remapping.
+ auto collect_memory_information()
+ {
+ auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map();
+ if (!memory_map)
+ {
+ system::panic("[x86_64] Failed to create early allocator, no memory map available.");
+ }
+
+ auto const & mbi = boot::bootstrap_information.mbi;
+ auto mbi_span = std::span{std::bit_cast<std::byte *>(mbi), mbi->size_bytes()};
+ auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical};
+
+ return x86_64::region_allocator::memory_information{
+ .image_range = std::make_pair(physical_address{&image_span.front()}, physical_address{&image_span.back()}),
+ .mbi_range = std::make_pair(physical_address{&mbi_span.front()}, physical_address{&mbi_span.back()}),
+ .memory_map = *memory_map,
+ };
+ }
+
+ //! Enable additional CPU protection features, required during later stages of the kernel.
+ auto enable_cpu_protections() -> void
+ {
+ cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect);
+ cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable);
+ }
+
+ //! Inject, or graft, a faux recursive PML4 into the active page mapping structure.
+ auto inject_faux_pml4(frame_allocator & allocator, page_mapper & mapper)
+ {
+ using namespace x86_64;
+ using entry_flags = page_table::entry::flags;
+
+ auto page = page::containing(unused_page_address);
+
+ auto temporary_mapper = scoped_mapping{page, mapper};
+ auto new_pml4_frame = allocator.allocate();
+
+ auto pml4 = std::construct_at(temporary_mapper.map_as<page_table>(*new_pml4_frame, entry_flags::writable));
+ (*pml4)[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable);
+
+ auto pml4_index = pml_index<4>(page);
+ auto old_pml4 = paging_root::get();
+ auto pml4_entry = (*old_pml4)[pml4_index];
+
+ auto pml3_index = pml_index<3>(page);
+ auto old_pml3 = old_pml4->next(pml4_index);
+ auto pml3_entry = (**old_pml3)[pml3_index];
+
+ auto pml2_index = pml_index<2>(page);
+ auto old_pml2 = (**old_pml3).next(pml3_index);
+ auto pml2_entry = (**old_pml2)[pml2_index];
+
+ auto pml1_index = pml_index<1>(page);
+ auto old_pml1 = (**old_pml2).next(pml2_index);
+ auto pml1_entry = (**old_pml1)[pml1_index];
+
+ (*paging_root::get())[recursive_page_map_index].frame(new_pml4_frame.value(),
+ entry_flags::present | entry_flags::writable);
+
+ tlb_flush_all();
+
+ auto new_pml4 = paging_root::get();
+ (*new_pml4)[pml4_index] = pml4_entry;
+
+ auto new_pml3 = new_pml4->next(pml4_index);
+ (**new_pml3)[pml3_index] = pml3_entry;
+
+ auto new_pml2 = (**new_pml3).next(pml3_index);
+ (**new_pml2)[pml2_index] = pml2_entry;
+
+ auto new_pml1 = (**new_pml2).next(pml2_index);
+ (**new_pml1)[pml1_index] = pml1_entry;
+
+ return *new_pml4_frame;
+ }
+
+ auto remap_kernel(page_mapper & mapper) -> void
+ {
+ auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi};
+ kernel_mapper.remap_kernel(mapper);
+ }
+
+ auto remap_vga_text_mode_buffer(page_mapper & mapper) -> void
+ {
+ constexpr auto vga_base = std::uintptr_t{0xb8000};
+ auto vga_physical_start = physical_address{vga_base};
+ auto vga_virtual_start = linear_address{vga_base + std::bit_cast<std::uintptr_t>(&boot::x86_64::TEACHOS_VMA)};
+
+ auto page = page::containing(vga_virtual_start);
+ auto frame = frame::containing(vga_physical_start);
+
+ mapper.map(page, frame, page_mapper::flags::writable);
+ }
+
+ auto remap_multiboot_information(page_mapper & mapper) -> void
+ {
+ auto mbi_base = std::bit_cast<std::uintptr_t>(boot::bootstrap_information.mbi);
+ auto mbi_size = boot::bootstrap_information.mbi->size_bytes();
+ auto mbi_physical_start = physical_address{mbi_base & ~std::bit_cast<std::uintptr_t>(&boot::x86_64::TEACHOS_VMA)};
+ auto mbi_virtual_start = linear_address{mbi_base};
+ auto mbi_block_count = (mbi_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE;
+
+ for (auto i = 0uz; i < mbi_block_count; ++i)
+ {
+ auto page = page::containing(mbi_virtual_start) + 1;
+ auto frame = frame::containing(mbi_physical_start) + 1;
+ mapper.map(page, frame, page_mapper::flags::empty);
+ }
+ }
+
+ } // namespace
+
+ // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
+ auto constinit region_based_allocator = std::optional<x86_64::region_allocator>{};
+ auto constinit buffered_allocator = std::optional<x86_64::buffered_allocator<4>>{};
+ auto constinit recursive_page_mapper = std::optional<x86_64::recursive_page_mapper>{};
+ // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
+
+ auto init() -> void
+ {
+ auto static constinit is_initialized = std::atomic_flag{};
+
+ if (is_initialized.test_and_set())
+ {
+ system::panic("[x86_64] Memory management has already been initialized.");
+ }
+
+ cio::println("[x86_64:MEM] Enabling additional CPU protection features.");
+
+ enable_cpu_protections();
+
+ region_based_allocator.emplace(collect_memory_information());
+ buffered_allocator.emplace(&*region_based_allocator);
+ recursive_page_mapper.emplace(*buffered_allocator);
+
+ cio::println("[x86_64:MEM] Preparing new paging hierarchy.");
+
+ auto new_pml4_frame = inject_faux_pml4(*buffered_allocator, *recursive_page_mapper);
+
+ remap_kernel(*recursive_page_mapper);
+ remap_vga_text_mode_buffer(*recursive_page_mapper);
+ remap_multiboot_information(*recursive_page_mapper);
+
+ cio::println("[x86_64:MEM] Switching to new paging hierarchy.");
+
+ auto cr3 = cpu::x86_64::cr3::read();
+ cr3.address(new_pml4_frame.start_address());
+ cpu::x86_64::cr3::write(cr3);
+
+ set_frame_allocator(*buffered_allocator);
+ set_page_mapper(*recursive_page_mapper);
+ }
+
+} // namespace teachos::memory
diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp
deleted file mode 100644
index 41b8cd7..0000000
--- a/arch/x86_64/src/kernel/cpu/control_register.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "arch/kernel/cpu/control_register.hpp"
-
-#include "arch/exception_handling/panic.hpp"
-
-#include <type_traits>
-
-namespace teachos::arch::kernel::cpu
-{
- auto read_control_register(control_register cr) -> uint64_t
- {
- uint64_t current_value;
- switch (cr)
- {
- case control_register::CR0:
- asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value));
- break;
- case control_register::CR2:
- asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value));
- break;
- case control_register::CR3:
- asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value));
- break;
- case control_register::CR4:
- asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value));
- break;
- }
- return current_value;
- }
-
- auto write_control_register(control_register cr, uint64_t new_value) -> void
- {
- switch (cr)
- {
- case control_register::CR0:
- asm volatile("mov %[input], %%cr0"
- : /* no output from call */
- : [input] "r"(new_value)
- : "memory");
- break;
- case control_register::CR2:
- asm volatile("mov %[input], %%cr2"
- : /* no output from call */
- : [input] "r"(new_value)
- : "memory");
- break;
- case control_register::CR3:
- asm volatile("mov %[input], %%cr3"
- : /* no output from call */
- : [input] "r"(new_value)
- : "memory");
- break;
- case control_register::CR4:
- asm volatile("mov %[input], %%cr4"
- : /* no output from call */
- : [input] "r"(new_value)
- : "memory");
- break;
- }
- }
-
- auto set_cr0_bit(cr0_flags flag) -> void
- {
- auto const cr0 = read_control_register(control_register::CR0);
- write_control_register(control_register::CR0, static_cast<std::underlying_type<cr0_flags>::type>(flag) | cr0);
- }
-} // namespace teachos::arch::kernel::cpu
diff --git a/arch/x86_64/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp
deleted file mode 100644
index 60a90a3..0000000
--- a/arch/x86_64/src/kernel/cpu/if.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace teachos::arch::kernel::cpu
-{
- auto set_interrupt_flag() -> void { asm volatile("sti"); }
-
- auto clear_interrupt_flag() -> void { asm volatile("cli"); }
-
-} // namespace teachos::arch::kernel::cpu
diff --git a/arch/x86_64/src/kernel/cpu/tlb.cpp b/arch/x86_64/src/kernel/cpu/tlb.cpp
deleted file mode 100644
index a09001c..0000000
--- a/arch/x86_64/src/kernel/cpu/tlb.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "arch/kernel/cpu/tlb.hpp"
-
-#include "arch/kernel/cpu/control_register.hpp"
-
-namespace teachos::arch::kernel::cpu
-{
- auto tlb_flush(memory::paging::virtual_address address) -> void
- {
- asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory");
- }
-
- auto tlb_flush_all() -> void
- {
- write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3));
- }
-} // namespace teachos::arch::kernel::cpu
diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
deleted file mode 100644
index a5a1b49..0000000
--- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "arch/memory/allocator/area_frame_allocator.hpp"
-
-#include "arch/exception_handling/assert.hpp"
-
-#include <algorithm>
-#include <array>
-#include <ranges>
-
-namespace teachos::arch::memory::allocator
-{
- area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info)
- : next_free_frame()
- , current_area(std::nullopt)
- , memory_areas(mem_info.areas)
- , kernel_start(physical_frame::containing_address(mem_info.kernel_start))
- , kernel_end(physical_frame::containing_address(mem_info.kernel_end))
- , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start))
- , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end))
- {
- choose_next_area();
- }
-
- auto area_frame_allocator::choose_next_area() -> void
- {
- current_area = std::nullopt;
- auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) {
- auto address = area.base_address + area.area_length - 1;
- return physical_frame::containing_address(address) >= next_free_frame;
- });
-
- auto const lowest_area_with_free_frames = std::ranges::min_element(
- next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; });
-
- if (lowest_area_with_free_frames != next_area_with_free_frames.end())
- {
- current_area = *lowest_area_with_free_frames;
- // Update the `next_free_frame` according to the new memory area
- auto const start_frame = physical_frame::containing_address(current_area.value().base_address);
- if (next_free_frame < start_frame)
- {
- next_free_frame = start_frame;
- }
- }
- }
-
- auto area_frame_allocator::allocate_frame() -> std::optional<physical_frame>
- {
- // Only try to allocate memory if current_area is not null, because
- // the current_area is null if there is no more available memory.
- if (!current_area.has_value())
- {
- return std::nullopt;
- }
-
- auto const address = current_area.value().base_address + current_area.value().area_length - 1;
- physical_frame current_area_last_frame = physical_frame::containing_address(address);
-
- if (next_free_frame > current_area_last_frame)
- {
- // All frames of current area are used, switch to next area.
- choose_next_area();
- }
- else if (next_free_frame >= kernel_start && next_free_frame <= kernel_end)
- {
- // `physical_frame` is used by the kernel or multiboot information structure.
- next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1};
- }
- else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end)
- {
- // `physical_frame` is used by the kernel or multiboot information structure.
- next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1};
- }
- else
- {
- // Frame is unused, increment `next_free_frame` and return it.
- next_free_frame.frame_number += 1;
- return next_free_frame;
- }
-
- // `physical_frame` was not valid, try it again with the updated `next_free_frame`.
- return allocate_frame();
- }
-
- auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { (void)physical_frame; }
-} // namespace teachos::arch::memory::allocator
diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp
deleted file mode 100644
index ec387a1..0000000
--- a/arch/x86_64/src/memory/allocator/physical_frame.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "arch/memory/allocator/physical_frame.hpp"
-
-namespace teachos::arch::memory::allocator
-{
- auto physical_frame::containing_address(physical_address address) -> physical_frame
- {
- return physical_frame{address / PAGE_FRAME_SIZE};
- }
-
- auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; }
-
- auto physical_frame::operator++(int) -> physical_frame
- {
- physical_frame const old_value = *this;
- ++frame_number;
- return old_value;
- }
-
- auto physical_frame::operator++() -> physical_frame &
- {
- ++frame_number;
- return *this;
- }
-} // namespace teachos::arch::memory::allocator
diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp
deleted file mode 100644
index 3cdf9c7..0000000
--- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "arch/memory/allocator/tiny_frame_allocator.hpp"
-
-#include "arch/exception_handling/panic.hpp"
-
-namespace teachos::arch::memory::allocator
-{
- auto tiny_frame_allocator::allocate_frame() -> std::optional<physical_frame>
- {
- for (auto & frame_option : frames)
- {
- if (frame_option.has_value())
- {
- auto value = frame_option;
- frame_option.reset();
- return value;
- }
- }
- return std::nullopt;
- }
-
- auto tiny_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void
- {
- for (auto & frame_option : frames)
- {
- if (!frame_option.has_value())
- {
- frame_option.emplace(physical_frame);
- return;
- }
- }
- exception_handling::panic(
- "[Tiny Frame Allocator] Attempted to deallocate more than the 3 frames, that can be held");
- }
-} // namespace teachos::arch::memory::allocator
diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp
new file mode 100644
index 0000000..4781d64
--- /dev/null
+++ b/arch/x86_64/src/memory/kernel_mapper.cpp
@@ -0,0 +1,111 @@
+#include "x86_64/memory/kernel_mapper.hpp"
+
+#include "kapi/cio.hpp"
+#include "kapi/memory.hpp"
+#include "kapi/system.hpp"
+
+#include "x86_64/boot/ld.hpp"
+
+#include <elf/format.hpp>
+#include <elf/section_header.hpp>
+#include <multiboot2/information.hpp>
+
+#include <algorithm>
+#include <array>
+#include <bit>
+#include <cstdint>
+#include <ranges>
+#include <string_view>
+#include <utility>
+
+namespace teachos::memory::x86_64
+{
+
+ namespace
+ {
+ using namespace std::string_view_literals;
+
+ constexpr auto static ignored_section_prefixes = std::array{
+ ".boot_"sv,
+ };
+
+ constexpr auto static user_accessible_prefixes = std::array{
+ ".user"sv,
+ ".stl"sv,
+ };
+
+ } // namespace
+
+ kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi)
+ : m_mbi{std::move(mbi)}
+ , m_kernel_load_base{std::bit_cast<std::uintptr_t>(&boot::x86_64::TEACHOS_VMA)}
+ {}
+
+ auto kernel_mapper::remap_kernel(page_mapper & mapper) -> void
+ {
+ auto elf_information = m_mbi->maybe_elf_symbols<elf::format::elf64>();
+ if (!elf_information)
+ {
+ system::panic("[x86_64:MEM] ELF section information is not available.");
+ }
+
+ auto sections = *elf_information;
+ auto allocated_sections =
+ std::views::all(sections) | std::views::filter(&elf::section_header<elf::format::elf64>::allocated) |
+ std::views::filter([&](auto const & section) -> auto {
+ auto name = sections.name(section);
+ return !std::ranges::any_of(ignored_section_prefixes,
+ [&](auto const & prefix) -> auto { return name.starts_with(prefix); });
+ });
+
+ if (allocated_sections.empty())
+ {
+ system::panic("[x86_64:MEM] No allocated ELF sections were found.");
+ }
+
+ std::ranges::for_each(allocated_sections,
+ [&](auto const & section) -> auto { map_section(section, sections.name(section), mapper); });
+ }
+
+ auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, page_mapper & mapper)
+ -> void
+ {
+ cio::print("[x86_64:MEM] mapping ");
+ cio::println(name);
+
+ auto number_of_pages = (section.size + (PLATFORM_PAGE_SIZE - 1)) / PLATFORM_PAGE_SIZE;
+
+ auto linear_start_address = linear_address{section.virtual_load_address};
+ auto physical_start_address = physical_address{section.virtual_load_address & ~m_kernel_load_base};
+
+ auto first_page = page::containing(linear_start_address);
+ auto first_frame = frame::containing(physical_start_address);
+
+ auto page_flags = page_mapper::flags::empty;
+
+ if (section.writable())
+ {
+ page_flags |= page_mapper::flags::writable;
+ }
+
+ if (section.executable())
+ {
+ page_flags |= page_mapper::flags::executable;
+ }
+
+ auto is_prefix_of_name = [=](auto prefix) -> bool {
+ return name.starts_with(prefix);
+ };
+
+ if (!std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name))
+ {
+ page_flags |= page_mapper::flags::supervisor_only;
+ }
+
+ for (auto i = 0uz; i < number_of_pages; ++i)
+ {
+ mapper.map(first_page + i, first_frame + i, page_flags);
+ }
+ }
+
+} // namespace teachos::memory::x86_64 \ No newline at end of file
diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp
deleted file mode 100644
index 2746a71..0000000
--- a/arch/x86_64/src/memory/main.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "arch/memory/main.hpp"
-
-#include "arch/exception_handling/assert.hpp"
-#include "arch/kernel/cpu/control_register.hpp"
-#include "arch/kernel/cpu/msr.hpp"
-#include "arch/memory/allocator/area_frame_allocator.hpp"
-#include "arch/memory/allocator/concept.hpp"
-#include "arch/memory/heap/global_heap_allocator.hpp"
-#include "arch/memory/paging/active_page_table.hpp"
-#include "arch/memory/paging/kernel_mapper.hpp"
-
-#include <optional>
-
-namespace teachos::arch::memory
-{
- namespace
- {
- static std::optional<allocator::area_frame_allocator> frame_allocator;
-
- auto create_frame_allocator(multiboot::memory_information const & memory_information)
- -> allocator::area_frame_allocator &
- {
- frame_allocator.emplace(memory_information);
- return frame_allocator.value();
- }
-
- auto get_frame_allocator() -> allocator::area_frame_allocator &
- {
- exception_handling::assert(frame_allocator.has_value(),
- "[Initialization] Frame allocator has not been created yet");
- return frame_allocator.value();
- }
- } // namespace
-
- auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void
- {
- decltype(auto) allocator = get_frame_allocator();
- decltype(auto) active_table = paging::active_page_table::create_or_get();
- auto const start_page = paging::virtual_page::containing_address(heap_start);
- auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1));
-
- paging::page_container::iterator const begin{start_page};
- paging::page_container::iterator const end{end_page};
- paging::page_container const pages{begin, end};
-
- constexpr auto base_flags = paging::entry::WRITABLE;
- auto const flags = base_flags | additional_flags;
-
- for (auto const & page : pages)
- {
- active_table.map_page_to_next_free_frame(allocator, page, flags);
- }
- }
-
- auto initialize_memory_management() -> void
- {
- static bool has_been_called = false;
- arch::exception_handling::assert(!has_been_called,
- "[Initialization] Memory management has already been initialized");
- has_been_called = true;
-
- auto const memory_information = multiboot::read_multiboot2();
- decltype(auto) allocator = create_frame_allocator(memory_information);
-
- kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT);
- kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE);
-
- paging::kernel_mapper kernel(allocator, memory_information);
- kernel.remap_kernel();
- video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black);
- video::vga::text::newline();
-
- remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE);
- video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black);
- video::vga::text::newline();
- }
-} // namespace teachos::arch::memory
diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp
new file mode 100644
index 0000000..e15d94e
--- /dev/null
+++ b/arch/x86_64/src/memory/mmu.cpp
@@ -0,0 +1,21 @@
+#include "x86_64/memory/mmu.hpp"
+
+#include "kapi/memory.hpp"
+
+#include "x86_64/cpu/registers.hpp"
+
+namespace teachos::memory::x86_64
+{
+ namespace cpu = cpu::x86_64;
+
+ auto tlb_flush(linear_address address) -> void
+ {
+ asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory");
+ }
+
+ auto tlb_flush_all() -> void
+ {
+ auto paging_root = cpu::cr3::read();
+ cpu::cr3::write(paging_root);
+ }
+} // namespace teachos::memory::x86_64
diff --git a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp
deleted file mode 100644
index f5d126b..0000000
--- a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "arch/memory/multiboot/elf_symbols_section.hpp"
-
-namespace teachos::arch::memory::multiboot
-{
- auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; }
-
- auto elf_section_header::is_null() const -> bool
- {
- return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == elf_section_flags(0U) &&
- physical_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U &&
- fixed_table_entry_size == 0U;
- }
-} // namespace teachos::arch::memory::multiboot
diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp
deleted file mode 100644
index 2bf5b25..0000000
--- a/arch/x86_64/src/memory/multiboot/reader.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-#include "arch/memory/multiboot/reader.hpp"
-
-#include "arch/boot/pointers.hpp"
-#include "arch/exception_handling/assert.hpp"
-#include "arch/memory/multiboot/elf_symbols_section.hpp"
-#include "arch/memory/multiboot/info.hpp"
-
-#include <algorithm>
-#include <ranges>
-
-namespace teachos::arch::memory::multiboot
-{
- namespace
- {
- template<typename T>
- requires std::is_pointer<T>::value
- auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T
- {
- return reinterpret_cast<T>(reinterpret_cast<uint8_t *>(ptr) + ((size + 7) & ~7));
- }
-
- auto process_memory_map(memory_map_header * mminfo) -> memory_area_container
- {
- auto const expected_entry_size = mminfo->entry_size;
- auto constexpr actual_entry_size = sizeof(memory_area);
- exception_handling::assert(expected_entry_size == actual_entry_size,
- "[Multiboot Reader] Unexpected memory area entry size");
-
- auto const total_size = mminfo->info.size;
- auto const total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size;
- auto const number_of_entries = total_entries_size / actual_entry_size;
-
- auto const begin = memory_area_container::iterator{&mminfo->entries};
- auto const end = begin + number_of_entries;
- return memory_area_container{begin, end};
- }
-
- auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start,
- std::size_t & kernel_end) -> elf_section_header_container
- {
- auto const expected_entry_size = symbol->entry_size;
- auto constexpr actual_entry_size = sizeof(elf_section_header);
- exception_handling::assert(expected_entry_size == actual_entry_size,
- "[Multiboot Reader] Unexpected elf section header entry size");
-
- auto const expected_total_size = symbol->info.size;
- auto const actual_total_entry_size = actual_entry_size * symbol->number_of_sections;
- auto constexpr actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t);
- auto const actual_total_size = actual_total_entry_size + actual_total_section_size;
- exception_handling::assert(expected_total_size == actual_total_size,
- "[Multiboot Reader] Unexpected elf symbols section header total size");
-
- auto const begin = elf_section_header_container::iterator{reinterpret_cast<elf_section_header *>(&symbol->end)};
- auto const end = begin + symbol->number_of_sections;
- exception_handling::assert(begin->is_null(),
- "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section");
-
- elf_section_header_container sections{begin, end};
-
- auto allocated_sections = sections | std::views::filter([](auto const & section) {
- return section.flags.contains_flags(elf_section_flags::OCCUPIES_MEMORY);
- });
-
- auto const elf_section_with_lowest_physical_address = std::ranges::min_element(
- allocated_sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; });
-
- auto const elf_section_with_highest_physical_address =
- std::ranges::max_element(allocated_sections, [](auto const & a, auto const & b) {
- auto a_physical_address_end = a.physical_address + a.section_size;
- auto b_physical_address_end = b.physical_address + b.section_size;
- return a_physical_address_end < b_physical_address_end;
- });
-
- auto const symbol_table_section_count = std::ranges::count_if(sections, [](auto const & section) {
- return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == elf_section_type::SYMBOL_TABLE;
- });
- auto const dynamic_section_count = std::ranges::count_if(
- sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; });
-
- exception_handling::assert(
- symbol_table_section_count == 1U,
- "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got more");
- exception_handling::assert(
- dynamic_section_count <= 1U,
- "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more");
-
- auto const lowest_elf_section = *elf_section_with_lowest_physical_address;
- kernel_start = lowest_elf_section.physical_address;
-
- auto const highest_elf_section = *elf_section_with_highest_physical_address;
- kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size;
-
- return sections;
- }
- } // namespace
-
- auto read_multiboot2() -> memory_information
- {
- memory_information mem_info{UINT64_MAX,
- 0U,
- elf_section_header_container{},
- boot::multiboot_information_pointer,
- 0U,
- memory_area_container{}};
-
- auto const multiboot_information_pointer = reinterpret_cast<info_header *>(boot::multiboot_information_pointer);
- auto const multiboot_tag = &multiboot_information_pointer->tags;
- mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size;
-
- for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size))
- {
- switch (tag->type)
- {
- case tag_type::ELF_SECTIONS: {
- auto const symbol = reinterpret_cast<elf_symbols_section_header *>(tag);
- mem_info.sections = process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end);
- break;
- }
- case tag_type::MEMORY_MAP: {
- auto const mminfo = reinterpret_cast<memory_map_header *>(tag);
- mem_info.areas = process_memory_map(mminfo);
- break;
- }
- default:
- // All other cases are not important and can be ignored.
- break;
- }
- }
- return mem_info;
- }
-} // namespace teachos::arch::memory::multiboot
diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp
new file mode 100644
index 0000000..2de099d
--- /dev/null
+++ b/arch/x86_64/src/memory/page_table.cpp
@@ -0,0 +1,82 @@
+#include "x86_64/memory/page_table.hpp"
+
+#include "kapi/memory.hpp"
+
+#include <algorithm>
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <optional>
+#include <utility>
+
+namespace teachos::memory::x86_64
+{
+
+ auto page_table::entry::clear() noexcept -> void
+ {
+ m_raw = 0;
+ }
+
+ auto page_table::entry::present() const noexcept -> bool
+ {
+ return (all_flags() & flags::present) != flags::empty;
+ }
+
+ auto page_table::entry::huge() const noexcept -> bool
+ {
+ return (all_flags() & flags::huge_page) != flags::empty;
+ }
+
+ auto page_table::entry::all_flags() const noexcept -> flags
+ {
+ return std::bit_cast<flags>(m_raw & ~frame_number_mask);
+ }
+
+ auto page_table::entry::all_flags(flags flags) noexcept -> void
+ {
+ m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags);
+ }
+
+ auto page_table::entry::operator|=(flags rhs) noexcept -> page_table::entry &
+ {
+ auto raw_flags = std::to_underlying(rhs) & ~frame_number_mask;
+ m_raw |= raw_flags;
+ return *this;
+ }
+
+ auto page_table::entry::frame() const noexcept -> std::optional<struct frame>
+ {
+ if (present())
+ {
+ return frame::containing(physical_address{m_raw & frame_number_mask});
+ }
+ return std::nullopt;
+ }
+
+ auto page_table::entry::frame(struct frame frame, flags flags) noexcept -> void
+ {
+ m_raw = (frame.start_address().raw() | static_cast<std::uint64_t>(flags));
+ };
+
+ auto page_table::operator[](std::size_t index) -> entry &
+ {
+ return m_entries.at(index);
+ }
+
+ auto page_table::operator[](std::size_t index) const -> entry const &
+ {
+ return m_entries.at(index);
+ }
+
+ auto page_table::clear() noexcept -> void
+ {
+ std::ranges::for_each(m_entries, &page_table::entry::clear);
+ }
+
+ auto page_table::empty() const noexcept -> bool
+ {
+ return std::ranges::all_of(m_entries,
+ [](auto const & entry) -> auto { return entry.all_flags() == entry::flags::empty; });
+ }
+
+} // namespace teachos::memory::x86_64
diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp
deleted file mode 100644
index 0113869..0000000
--- a/arch/x86_64/src/memory/paging/active_page_table.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "arch/memory/paging/active_page_table.hpp"
-
-namespace teachos::arch::memory::paging
-{
- namespace
- {
- paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000;
- }
-
- auto active_page_table::create_or_get() -> active_page_table &
- {
- static page_table_handle active_handle{reinterpret_cast<page_table *>(PAGE_TABLE_LEVEL_4_ADDRESS),
- page_table_handle::LEVEL4};
- static active_page_table active_page{active_handle};
- return active_page;
- }
-
- auto active_page_table::operator[](std::size_t index) -> entry & { return active_handle[index]; }
-
- auto active_page_table::translate_address(virtual_address address) -> std::optional<allocator::physical_address>
- {
- auto const offset = address % allocator::PAGE_FRAME_SIZE;
- auto const page = virtual_page::containing_address(address);
- auto const frame = translate_page(page);
-
- if (frame.has_value())
- {
- return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset;
- }
-
- return std::nullopt;
- }
-
- auto active_page_table::translate_page(virtual_page page) -> std::optional<allocator::physical_frame>
- {
- auto current_handle = active_handle;
-
- for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level)
- {
- auto const next_handle = current_handle.next_table(page.get_level_index(level));
- // If the next table method failed then it is highly likely that it was a huge page and we therefore have to
- // parse the table differently. Therefore, we attempt to parse it using the method required by huge pages.
- if (!next_handle.has_value())
- {
- return translate_huge_page(page);
- }
- current_handle = next_handle.value();
- }
-
- auto const level1_index = page.get_level_index(page_table_handle::LEVEL1);
- auto const level1_entry = current_handle[level1_index];
- return level1_entry.calculate_pointed_to_frame();
- }
-
- auto active_page_table::translate_huge_page(virtual_page page) -> std::optional<allocator::physical_frame>
- {
- auto current_handle = active_handle;
- auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4));
-
- if (!level3_handle.has_value())
- {
- return std::nullopt;
- }
-
- auto const level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)];
- auto const level3_frame = level3_entry.calculate_pointed_to_frame();
- if (level3_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE))
- {
- exception_handling::assert(
- level3_frame.value().frame_number % (PAGE_TABLE_ENTRY_COUNT * PAGE_TABLE_ENTRY_COUNT) == 0U,
- "[Page Mapper] Physical address must be 1 GiB aligned");
- return allocator::physical_frame{level3_frame.value().frame_number +
- page.get_level_index(page_table_handle::LEVEL2) * PAGE_TABLE_ENTRY_COUNT +
- page.get_level_index(page_table_handle::LEVEL1)};
- }
-
- auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3));
- if (level2_handle.has_value())
- {
- auto const level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)];
- auto const level2_frame = level2_entry.calculate_pointed_to_frame();
- if (level2_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE))
- {
- exception_handling::assert(level2_frame.value().frame_number % PAGE_TABLE_ENTRY_COUNT == 0U,
- "[Page Mapper] Physical address must be 2 MiB aligned");
- return allocator::physical_frame{level2_frame.value().frame_number +
- page.get_level_index(page_table_handle::LEVEL1)};
- }
- }
- return std::nullopt;
- }
-
- active_page_table::active_page_table(page_table_handle active_handle)
- : active_handle(active_handle)
- {
- // Nothing to do
- }
-} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp
deleted file mode 100644
index 4e0610e..0000000
--- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "arch/memory/paging/inactive_page_table.hpp"
-
-namespace teachos::arch::memory::paging
-{
- inactive_page_table::inactive_page_table(allocator::physical_frame frame)
- : page_table_level_4_frame{frame}
- {
- // Nothing to do
- }
-
- inactive_page_table::inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table,
- temporary_page & temporary_page)
- : page_table_level_4_frame{frame}
- {
- auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table);
- table.zero_entries();
- table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE);
- temporary_page.unmap_page(active_page_table);
- }
-} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp
deleted file mode 100644
index 57045ca..0000000
--- a/arch/x86_64/src/memory/paging/page_entry.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "arch/memory/paging/page_entry.hpp"
-
-#include "arch/exception_handling/assert.hpp"
-
-namespace teachos::arch::memory::paging
-{
- namespace
- {
- std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000;
- } // namespace
-
- entry::entry(uint64_t flags)
- : flags(flags)
- {
- // Nothing to do.
- }
-
- entry::entry(multiboot::elf_section_flags elf_flags)
- {
- if (elf_flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY))
- {
- flags |= entry::PRESENT;
- }
-
- if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE))
- {
- flags |= entry::WRITABLE;
- }
-
- if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE))
- {
- flags |= entry::EXECUTING_CODE_FORBIDDEN;
- }
- }
-
- auto entry::is_unused() const -> bool { return flags == 0U; }
-
- auto entry::set_unused() -> void { flags = 0U; }
-
- auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; }
-
- auto entry::calculate_pointed_to_frame() const -> std::optional<allocator::physical_frame>
- {
- if (contains_flags(PRESENT))
- {
- auto const address = flags.to_ulong() & PHYSICAL_ADDRESS_MASK;
- return allocator::physical_frame::containing_address(address);
- }
- return std::nullopt;
- }
-
- auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; }
-
- auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void
- {
- exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0,
- "[Paging Entry] Start address is not aligned with page");
-
- flags = frame.start_address() | additional_flags.to_ulong();
- }
-
- auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; }
-} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp
deleted file mode 100644
index eb11810..0000000
--- a/arch/x86_64/src/memory/paging/page_table.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "arch/memory/paging/page_table.hpp"
-
-#include <algorithm>
-#include <array>
-#include <memory>
-
-/*
- * This is a linker variable reference. This referenc cannot reside inside a namespace, because in
- * that case the compiler would try to find arch::memory::paging::_end_of_image inside the ELF file.
- */
-extern char _end_of_image;
-
-namespace teachos::arch::memory::paging
-{
- /**
- * @brief A Page table containing 512 entries.
- */
- struct page_table
- {
- auto zero_entries() -> void;
-
- auto is_empty() const -> bool;
-
- auto next_table(std::size_t table_index) const -> std::optional<page_table *>;
-
- auto operator[](std::size_t index) -> entry &;
-
- auto operator[](std::size_t index) const -> entry const &;
-
- private:
- /**
- * @brief Calculates the address of the next page table level for the given table index.
- *
- * @note The next page table address is only valid if the corresponding entry is present and not a huge page.
- * Meaning we use an index into a Level 4 page table to get the according Level 3 page table address.
- *
- * @param table_index Index of this page table in the page table one level higher.
- * @return An optional of the address of the next page table or null.
- */
- auto next_table_address(std::size_t table_index) const -> std::optional<std::size_t>;
-
- std::array<entry, PAGE_TABLE_ENTRY_COUNT> entries =
- {}; ///< Entries containing addresses to page tables of a level below or
- ///< actual virtual addresses for the level 1 page table.
- };
-
- auto page_table::zero_entries() -> void
- {
- std::ranges::for_each(entries, [](auto & entry) { entry.set_unused(); });
- }
-
- auto page_table::is_empty() const -> bool
- {
- return std::all_of(entries.begin(), entries.end(), [](entry const & entry) { return entry.is_unused(); });
- }
-
- auto page_table::next_table(std::size_t table_index) const -> std::optional<page_table *>
- {
- auto const address = next_table_address(table_index);
- if (address.has_value())
- {
- return reinterpret_cast<page_table *>(address.value());
- }
- return std::nullopt;
- }
-
- auto page_table::operator[](std::size_t index) -> entry &
- {
- exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds");
- return entries[index];
- }
-
- auto page_table::operator[](std::size_t index) const -> entry const &
- {
- exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds");
- return entries[index];
- }
-
- auto page_table::next_table_address(std::size_t table_index) const -> std::optional<std::size_t>
- {
- auto const entry = this->operator[](table_index);
-
- if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE))
- {
- auto const table_address = reinterpret_cast<std::size_t>(this);
- return ((table_address << 9) | (table_index << 12));
- }
- return std::nullopt;
- }
-
- page_table_handle::page_table_handle(page_table * table, page_table_handle::level table_level)
- : table(table)
- , table_level(table_level)
- {
- exception_handling::assert(table != nullptr,
- "[Page Table] Attempted to pass nullptr as table to page table table method");
- }
-
- auto page_table_handle::zero_entries() -> void { table->zero_entries(); }
-
- auto page_table_handle::is_empty() const -> bool { return table->is_empty(); }
-
- auto page_table_handle::next_table(std::size_t table_index) const -> std::optional<page_table_handle>
- {
- exception_handling::assert(table_level != page_table_handle::LEVEL1,
- "[Page Table] Attempted to call next_table on level 1 page table");
- auto const next_table = table->next_table(table_index);
- if (next_table.has_value())
- {
- auto const new_level = static_cast<page_table_handle::level>(table_level - 1);
- return page_table_handle{next_table.value(), new_level};
- }
- return std::nullopt;
- }
-
- auto page_table_handle::get_level() const -> page_table_handle::level { return table_level; }
-
- auto page_table_handle::operator[](std::size_t index) -> entry & { return table->operator[](index); }
-
- auto operator--(page_table_handle::level & value) -> page_table_handle::level &
- {
- exception_handling::assert(value != page_table_handle::LEVEL1,
- "[Page table] Attempted to decrement enum to value outside of range");
- auto new_value = static_cast<std::underlying_type<page_table_handle::level>::type>(value);
- value = static_cast<page_table_handle::level>(--new_value);
- return value;
- }
-} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp
deleted file mode 100644
index 8e73523..0000000
--- a/arch/x86_64/src/memory/paging/temporary_page.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "arch/memory/paging/temporary_page.hpp"
-
-#include "arch/memory/paging/page_entry.hpp"
-
-namespace teachos::arch::memory::paging
-{
- auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table)
- -> page_table_handle
- {
- page_table_handle handle{reinterpret_cast<page_table *>(map_to_frame(frame, active_table)),
- page_table_handle::LEVEL1};
- return handle;
- }
-
- auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table)
- -> virtual_address
- {
- exception_handling::assert(!active_table.translate_page(page).has_value(),
- "[Temporary page] Page is already mapped");
-
- active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE);
- return page.start_address();
- }
-
- auto temporary_page::unmap_page(active_page_table & active_table) -> void
- {
- active_table.unmap_page(allocator, page);
- }
-} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp
deleted file mode 100644
index d374156..0000000
--- a/arch/x86_64/src/memory/paging/virtual_page.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "arch/memory/paging/virtual_page.hpp"
-
-#include "arch/exception_handling/assert.hpp"
-
-namespace teachos::arch::memory::paging
-{
- auto virtual_page::containing_address(virtual_address address) -> virtual_page
- {
- exception_handling::assert(address < 0x00008000'00000000 || address >= 0xffff8000'00000000,
- "[Virtual Page] Attempted to create virtual page from invalid address");
- return virtual_page{address / allocator::PAGE_FRAME_SIZE};
- }
-
- auto virtual_page::start_address() const -> virtual_address { return page_number * allocator::PAGE_FRAME_SIZE; }
-
- auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t
- {
- return (page_number >> (level * 9U)) & 0x1FF;
- }
-
- auto virtual_page::operator++(int) -> virtual_page
- {
- virtual_page const old_value = *this;
- ++page_number;
- return old_value;
- }
-
- auto virtual_page::operator++() -> virtual_page &
- {
- ++page_number;
- return *this;
- }
-} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp
new file mode 100644
index 0000000..d849a82
--- /dev/null
+++ b/arch/x86_64/src/memory/paging_root.cpp
@@ -0,0 +1,19 @@
+#include "x86_64/memory/paging_root.hpp"
+
+#include <bit>
+#include <cstdint>
+
+namespace teachos::memory::x86_64
+{
+
+ namespace
+ {
+ constexpr auto recursive_base = std::uintptr_t{0177777'776'776'776'776'0000uz};
+ } // namespace
+
+ auto paging_root::get() -> paging_root *
+ {
+ return std::bit_cast<paging_root *>(recursive_base);
+ }
+
+} // namespace teachos::memory::x86_64 \ No newline at end of file
diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp
new file mode 100644
index 0000000..c5aabcb
--- /dev/null
+++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp
@@ -0,0 +1,119 @@
+#include "x86_64/memory/recursive_page_mapper.hpp"
+
+#include "kapi/memory.hpp"
+#include "kapi/system.hpp"
+
+#include "x86_64/memory/page_table.hpp"
+#include "x86_64/memory/page_utilities.hpp"
+#include "x86_64/memory/paging_root.hpp"
+
+#include <cstddef>
+#include <optional>
+
+namespace teachos::memory::x86_64
+{
+ namespace
+ {
+ //! Perform the actual mapping of the page, via the recursive page map.
+ //!
+ //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries
+ //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When
+ //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit
+ //! added, thus still enforcing non-writability and non-execution of the affected page.
+ template<std::size_t Level>
+ requires(Level > 1uz && Level <= PLATFORM_PAGING_LEVELS)
+ auto do_map(recursive_page_table<Level> * pml, page page, frame_allocator & allocator, page_mapper::flags flags)
+ {
+ auto index = pml_index<Level>(page);
+ auto entry_flags = to_table_flags(flags);
+
+ entry_flags = entry_flags & ~page_table::entry::flags::no_execute;
+ entry_flags = entry_flags | page_table::entry::flags::writable;
+ if (!(*pml)[index].present())
+ {
+ auto new_table_frame = allocator.allocate();
+ (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | entry_flags);
+ auto new_table = std::optional{std::construct_at(*pml->next(index))};
+ return new_table;
+ }
+ (*pml)[index] |= entry_flags;
+ return pml->next(index);
+ }
+
+ //! Perform the actual PML1 update.
+ auto do_map(page_table * pml, page page, frame frame, page_mapper::flags flags) -> std::optional<std::byte *>
+ {
+ auto index = pml_index<1>(page);
+ if ((*pml)[index].present())
+ {
+ system::panic("[x86_64:MEM] Tried to map a page that is already mapped");
+ }
+ (*pml)[index].frame(frame, page_table::entry::flags::present | to_table_flags(flags));
+ return std::optional{static_cast<std::byte *>(page.start_address())};
+ }
+
+ } // namespace
+
+ recursive_page_mapper::recursive_page_mapper(frame_allocator & allocator)
+ : m_allocator{&allocator}
+ {}
+
+ auto recursive_page_mapper::map(page page, frame frame, flags flags) -> std::byte *
+ {
+ auto pml4 = static_cast<recursive_page_table<4> *>((paging_root::get()));
+
+ return std::optional{pml4}
+ .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); })
+ .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); })
+ .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); })
+ .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); })
+ .value_or(nullptr);
+ }
+
+ auto recursive_page_mapper::unmap(page page) -> void
+ {
+ if (!try_unmap(page))
+ {
+ system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped.");
+ }
+ }
+
+ auto recursive_page_mapper::try_unmap(page page) noexcept -> bool
+ {
+ if (!paging_root::get()->translate(page))
+ {
+ return false;
+ }
+
+ auto pml4 = paging_root::get();
+ auto pml3 = pml4->next(pml_index<4>(page)).value();
+ auto pml2 = pml3->next(pml_index<3>(page)).value();
+ auto pml1 = pml2->next(pml_index<2>(page)).value();
+
+ (*pml1)[pml_index<1>(page)].clear();
+
+ if (pml1->empty())
+ {
+ auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value();
+ m_allocator->release(pml1_frame);
+ (*pml2)[pml_index<2>(page)].clear();
+ }
+
+ if (pml2->empty())
+ {
+ auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value();
+ m_allocator->release(pml2_frame);
+ (*pml3)[pml_index<3>(page)].clear();
+ }
+
+ if (pml3->empty())
+ {
+ auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value();
+ m_allocator->release(pml3_frame);
+ (*pml4)[pml_index<4>(page)].clear();
+ }
+
+ return true;
+ }
+
+} // namespace teachos::memory::x86_64 \ No newline at end of file
diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp
new file mode 100644
index 0000000..0f65b3a
--- /dev/null
+++ b/arch/x86_64/src/memory/region_allocator.cpp
@@ -0,0 +1,92 @@
+#include "x86_64/memory/region_allocator.hpp"
+
+#include "kapi/memory/address.hpp"
+#include "kapi/memory/frame.hpp"
+
+#include <multiboot2/information.hpp>
+
+#include <algorithm>
+#include <optional>
+#include <ranges>
+#include <utility>
+
+namespace teachos::memory::x86_64
+{
+ namespace
+ {
+ constexpr auto last_frame(multiboot2::memory_map::region const & region)
+ {
+ return frame::containing(physical_address{region.base + region.size_in_B - 1});
+ }
+
+ constexpr auto falls_within(frame const & candidate, frame const & start, frame const & end)
+ {
+ return candidate >= start && candidate <= end;
+ }
+ } // namespace
+
+ region_allocator::region_allocator(memory_information const & mem_info)
+ : m_next_frame{}
+ , m_current_region{}
+ , m_memory_map{mem_info.memory_map}
+ , m_kernel_start(frame::containing(mem_info.image_range.first))
+ , m_kernel_end(frame::containing(mem_info.image_range.second))
+ , m_multiboot_start(frame::containing(mem_info.mbi_range.first))
+ , m_multiboot_end(frame::containing(mem_info.mbi_range.second))
+ {
+ choose_next_area();
+ }
+
+ auto region_allocator::choose_next_area() -> void
+ {
+ m_current_region.reset();
+ auto next_area_with_free_frames =
+ m_memory_map | std::views::filter(&multiboot2::memory_map::region::available) |
+ std::views::filter([next = m_next_frame](auto const & region) -> bool { return last_frame(region) >= next; });
+
+ auto lowest_region_with_free_frames = std::ranges::min_element(
+ next_area_with_free_frames, [](auto lhs, auto rhs) -> bool { return lhs.base < rhs.base; });
+
+ if (lowest_region_with_free_frames != next_area_with_free_frames.end())
+ {
+ m_current_region = *lowest_region_with_free_frames;
+ auto start_frame = frame::containing(physical_address{m_current_region->base});
+ if (m_next_frame < start_frame)
+ {
+ m_next_frame = start_frame;
+ }
+ }
+ }
+
+ auto region_allocator::allocate() noexcept -> std::optional<frame>
+ {
+ if (!m_current_region)
+ {
+ return {};
+ }
+
+ auto const end_address = physical_address{m_current_region->base + m_current_region->size_in_B - 1};
+ auto end_frame = frame::containing(end_address);
+
+ if (m_next_frame > end_frame)
+ {
+ choose_next_area();
+ }
+ else if (falls_within(m_next_frame, m_kernel_start, m_kernel_end))
+ {
+ m_next_frame = m_kernel_end + 1;
+ }
+ else if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end))
+ {
+ m_next_frame = m_multiboot_end + 1;
+ }
+ else
+ {
+ return m_next_frame++;
+ }
+
+ return allocate();
+ }
+
+ auto region_allocator::release(frame) -> void {}
+} // namespace teachos::memory::x86_64
diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp
new file mode 100644
index 0000000..a86aaed
--- /dev/null
+++ b/arch/x86_64/src/memory/scoped_mapping.cpp
@@ -0,0 +1,69 @@
+#include "x86_64/memory/scoped_mapping.hpp"
+
+#include "kapi/memory.hpp"
+#include "kapi/system.hpp"
+
+#include "x86_64/memory/mmu.hpp"
+#include "x86_64/memory/page_table.hpp"
+#include "x86_64/memory/paging_root.hpp"
+
+#include <cstddef>
+#include <utility>
+
+namespace teachos::memory::x86_64
+{
+
+ scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept
+ : m_page{std::exchange(other.m_page, page{})}
+ , m_mapper{std::exchange(other.m_mapper, nullptr)}
+ , m_mapped{std::exchange(other.m_mapped, false)}
+ {}
+
+ scoped_mapping::scoped_mapping(page page, page_mapper & mapper)
+ : m_page{page}
+ , m_mapper{&mapper}
+ , m_mapped{false}
+ {
+ if (paging_root::get()->translate(page))
+ {
+ system::panic("[MEM] Tried to map a page that is already mapped!");
+ }
+ }
+
+ scoped_mapping::~scoped_mapping()
+ {
+ if (m_mapped)
+ {
+ unmap();
+ x86_64::tlb_flush(m_page.start_address());
+ }
+ }
+
+ auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping &
+ {
+ swap(*this, other);
+ return *this;
+ }
+
+ auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte *
+ {
+ auto result = m_mapper->map(m_page, frame, to_mapper_flags(flags));
+ m_mapped = true;
+ return result;
+ }
+
+ auto scoped_mapping::unmap() -> void
+ {
+ m_mapper->unmap(m_page);
+ m_mapped = false;
+ }
+
+ auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void
+ {
+ using std::swap;
+ swap(lhs.m_page, rhs.m_page);
+ swap(lhs.m_mapper, rhs.m_mapper);
+ swap(lhs.m_mapped, rhs.m_mapped);
+ }
+
+} // namespace teachos::memory::x86_64 \ No newline at end of file
diff --git a/arch/x86_64/src/stl/mutex.cpp b/arch/x86_64/src/stl/mutex.cpp
deleted file mode 100644
index 232a11c..0000000
--- a/arch/x86_64/src/stl/mutex.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "arch/stl/mutex.hpp"
-
-namespace teachos::arch::stl
-{
- auto mutex::lock() -> void
- {
- while (!try_lock())
- {
- // Nothing to do
- }
- }
-
- auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); }
-
- auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); }
-} // namespace teachos::arch::stl
diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp
new file mode 100644
index 0000000..c9eee71
--- /dev/null
+++ b/arch/x86_64/src/vga/text.cpp
@@ -0,0 +1,84 @@
+#include "x86_64/vga/text.hpp"
+
+#include "kapi/boot.hpp"
+
+#include "x86_64/boot/boot.hpp"
+#include "x86_64/boot/ld.hpp"
+#include "x86_64/vga/crtc.hpp"
+
+#include <algorithm>
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <span>
+#include <string_view>
+#include <utility>
+
+namespace teachos::vga::x86_64::text
+{
+ namespace
+ {
+ constexpr auto BUFFER_BASE_ADDRESS = std::uintptr_t{0xb8000};
+ constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U;
+ constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U;
+ constexpr auto CURSOR_ENABLED_BIT = 5U;
+ } // namespace
+
+ std::span<device::glyph> const device::buffer =
+ std::span{std::bit_cast<device::glyph *>(BUFFER_BASE_ADDRESS +
+ std::bit_cast<std::uintptr_t>(&teachos::boot::x86_64::TEACHOS_VMA)),
+ DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT};
+
+ device::device()
+ : m_position{boot::bootstrap_information.vga_buffer_index}
+ {}
+
+ auto device::clear(attribute attribute) -> void
+ {
+ m_position = 0;
+ std::ranges::fill(buffer, std::pair{' ', std::bit_cast<std::byte>(attribute)});
+ }
+
+ auto device::cursor(bool enabled) -> void
+ {
+ auto cursor_disable_byte = std::byte{!enabled} << CURSOR_ENABLED_BIT;
+
+ crtc::address::write(crtc::registers::cursor_start);
+ crtc::data::write(crtc::data::read() | cursor_disable_byte);
+ }
+
+ auto device::newline() -> void
+ {
+ auto current_line = m_position / DEFAULT_TEXT_BUFFER_WIDTH;
+ auto next_line = current_line + 1;
+
+ if (std::cmp_greater_equal(next_line, DEFAULT_TEXT_BUFFER_HEIGHT))
+ {
+ auto begin = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH;
+ auto end = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT;
+ std::ranges::move(begin, end, buffer.begin());
+ m_position = current_line * DEFAULT_TEXT_BUFFER_WIDTH;
+ }
+ else
+ {
+ m_position = next_line * DEFAULT_TEXT_BUFFER_WIDTH;
+ }
+ }
+
+ auto device::write(std::string_view code_points, attribute attribute) -> void
+ {
+ std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); });
+ }
+
+ auto device::write(char code_point, attribute attribute) -> void
+ {
+ buffer[m_position++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)};
+ };
+
+ auto device::writeln(std::string_view code_points, attribute attribute) -> void
+ {
+ std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); });
+ newline();
+ }
+
+} // namespace teachos::vga::x86_64::text
diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp
deleted file mode 100644
index b070a0a..0000000
--- a/arch/x86_64/src/video/vga/text.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "arch/video/vga/text.hpp"
-
-#include "arch/video/vga/io.hpp"
-#include "memory/asm_pointer.hpp"
-
-#include <algorithm>
-#include <string_view>
-#include <utility>
-
-extern "C" std::pair<char, teachos::arch::video::vga::text::attribute> * vga_buffer_pointer;
-
-namespace teachos::arch::video::vga::text
-{
- namespace
- {
- auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U;
- auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U;
-
- auto constinit text_buffer = teachos::memory::asm_pointer{vga_buffer_pointer};
- } // namespace
-
- auto clear(attribute attribute) -> void
- {
- *text_buffer = reinterpret_cast<decltype(text_buffer)::pointer>(DEFAULT_VGA_TEXT_BUFFER_ADDRESS);
- std::ranges::fill_n(*text_buffer, 2000, std::pair{' ', attribute});
- }
-
- auto cursor(bool enabled) -> void
- {
- auto cursor_disable_byte = std::byte{!enabled} << 5;
-
- crtc::address_port::write(crtc::registers::cursor_start);
- crtc::data_port::write(vga::crtc::data_port::read() | cursor_disable_byte);
- }
-
- auto newline() -> void
- {
- auto base = reinterpret_cast<decltype(text_buffer)::pointer>(DEFAULT_VGA_TEXT_BUFFER_ADDRESS);
- auto & raw_buffer = *text_buffer;
- auto current_line = (raw_buffer - base) / DEFAULT_TEXT_BUFFER_WIDTH;
- auto next_line = current_line + 1;
-
- if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT)
- {
- auto begin = base + DEFAULT_TEXT_BUFFER_WIDTH;
- auto end = base + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT;
- std::ranges::move(begin, end, base);
- raw_buffer = base + current_line * DEFAULT_TEXT_BUFFER_WIDTH;
- }
- else
- {
- raw_buffer = base + next_line * DEFAULT_TEXT_BUFFER_WIDTH;
- }
- }
-
- auto write_char(char code_point, attribute attribute) -> void
- {
- auto & p = *text_buffer;
- (*p++) = std::pair{code_point, attribute};
- };
-
- auto write(std::string_view code_points, attribute attribute) -> void
- {
- std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); });
- }
-} // namespace teachos::arch::video::vga::text
diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in
index 86674dd..49f19ce 100644
--- a/arch/x86_64/support/grub.cfg.in
+++ b/arch/x86_64/support/grub.cfg.in
@@ -2,6 +2,6 @@ timeout=2
default=0
menuentry "TeachOS" {
- multiboot2 /$<TARGET_FILE_NAME:teachos::kernel>
+ multiboot2 /$<TARGET_FILE_NAME:kernel>
boot
} \ No newline at end of file
diff --git a/arch/x86_64/x86_64.dox b/arch/x86_64/x86_64.dox
new file mode 100644
index 0000000..c5c218c
--- /dev/null
+++ b/arch/x86_64/x86_64.dox
@@ -0,0 +1,14 @@
+//! @namespace teachos::boot::x86_64
+//! The %x86_64 implementation of teachos::boot
+//!
+//! This namespace contains %x86_64 specific implementations of and extensions to the teachos::boot namespace.
+
+//! @namespace teachos::cpu::x86_64
+//! The %x86_64 implementation of teachos::cpu
+//!
+//! This namespace contains %x86_64 specific implementations of and extensions to the teachos::cpu namespace.
+
+//! @namespace teachos::memory::x86_64
+//! The %x86_64 implementation of teachos::memory
+//!
+//! This namespace contains %x86_64 specific implementations of and extensions to the teachos::memory namespace. \ No newline at end of file
diff --git a/cmake/Modules/ElfTransformations.cmake b/cmake/Modules/ElfTransformations.cmake
new file mode 100644
index 0000000..dfc8576
--- /dev/null
+++ b/cmake/Modules/ElfTransformations.cmake
@@ -0,0 +1,36 @@
+include_guard(GLOBAL)
+
+function(target_extract_debug_symbols TARGET)
+ add_custom_command(TARGET "${TARGET}"
+ POST_BUILD
+ COMMAND "${CMAKE_OBJCOPY}"
+ "--only-keep-debug"
+ "$<TARGET_FILE:${TARGET}>"
+ "$<TARGET_FILE_DIR:${TARGET}>/$<TARGET_FILE_BASE_NAME:${TARGET}>.sym"
+ BYPRODUCTS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIGURATION>/${TARGET}.sym"
+ COMMENT "Extracting debug symbols from $<TARGET_FILE:${TARGET}> ..."
+ )
+endfunction()
+
+function(target_strip TARGET)
+ add_custom_command(TARGET "${TARGET}"
+ POST_BUILD
+ COMMAND "${CMAKE_STRIP}"
+ "$<TARGET_FILE:${TARGET}>"
+ COMMENT "Stripping $<TARGET_FILE:${TARGET}> ..."
+ )
+endfunction()
+
+function(target_disassemble TARGET)
+ add_custom_command(TARGET "${TARGET}"
+ POST_BUILD
+ COMMAND "${CMAKE_OBJDUMP}"
+ "--disassemble"
+ "--visualize-jumps"
+ "--demangle"
+ "$<TARGET_FILE:${TARGET}>"
+ ">$<TARGET_FILE_DIR:${TARGET}>/$<TARGET_FILE_BASE_NAME:${TARGET}>.dis"
+ BYPRODUCTS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIGURATION>/${TARGET}.dis"
+ COMMENT "Dumping disassembly for $<TARGET_FILE:${TARGET}> ..."
+ )
+endfunction()
diff --git a/cmake/Modules/GenerateBootableIso.cmake b/cmake/Modules/GenerateBootableIso.cmake
new file mode 100644
index 0000000..3d1ee30
--- /dev/null
+++ b/cmake/Modules/GenerateBootableIso.cmake
@@ -0,0 +1,22 @@
+include_guard(GLOBAL)
+
+function(target_generate_bootable_iso TARGET)
+ find_package("grub-mkrescue")
+
+ file(GENERATE
+ OUTPUT "$<TARGET_FILE_DIR:${TARGET}>/isofs/boot/grub/grub.cfg"
+ INPUT "${PROJECT_SOURCE_DIR}/arch/${CMAKE_SYSTEM_PROCESSOR}/support/grub.cfg.in"
+ )
+
+ add_custom_command(TARGET "${TARGET}"
+ POST_BUILD
+ COMMAND "${GRUB_MKRESCUE_EXE}"
+ "-o"
+ "$<TARGET_FILE_DIR:${TARGET}>/${TARGET}.iso"
+ "$<TARGET_FILE_DIR:${TARGET}>/isofs"
+ "$<TARGET_FILE:${TARGET}>"
+ "2>/dev/null"
+ BYPRODUCTS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIGURATION>/${TARGET}.iso"
+ COMMENT "Creating bootable ISO image"
+ )
+endfunction()
diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake
index e0518b5..b17fec8 100644
--- a/cmake/Platforms/x86_64.cmake
+++ b/cmake/Platforms/x86_64.cmake
@@ -1,35 +1,41 @@
-execute_process(COMMAND "x86_64-pc-elf-g++" "-mno-red-zone" "-print-file-name=crtbegin.o"
- OUTPUT_VARIABLE CRT_BEGIN
- ERROR_QUIET
-)
-string(STRIP "${CRT_BEGIN}" CRT_BEGIN)
-mark_as_advanced(CRT_BEGIN)
-
-string(REGEX REPLACE "/crtbegin.o" "" CMAKE_SYSROOT "${CRT_BEGIN}")
-mark_as_advanced(CMAKE_SYSROOT)
+include_guard(GLOBAL)
-set(SYSTEM_NAME "Generic")
+set(PLATFORM_TARGET "x86_64-pc-elf")
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
-set(CMAKE_C_COMPILER "x86_64-pc-elf-gcc")
-set(CMAKE_CXX_COMPILER "x86_64-pc-elf-g++")
+set(CMAKE_SYSTEM_NAME "Generic-ELF")
+set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+
+set(CMAKE_ASM_COMPILER_TARGET "${PLATFORM_TARGET}")
+set(CMAKE_CXX_COMPILER_TARGET "${PLATFORM_TARGET}")
+
+find_program(CMAKE_ASM_COMPILER "${CMAKE_ASM_COMPILER_TARGET}-g++" REQUIRED)
+find_program(CMAKE_CXX_COMPILER "${CMAKE_CXX_COMPILER_TARGET}-g++" REQUIRED)
+
+set(CMAKE_CXX_FLAGS_INIT
+ "-mno-red-zone"
+ "-mcmodel=kernel"
+ "-fno-pie"
+ "-fno-rtti"
+ "-fno-exceptions"
+ "-fno-use-cxa-atexit"
+ "-ffunction-sections"
+ "-fdata-sections"
+)
+
+list(JOIN CMAKE_CXX_FLAGS_INIT " " CMAKE_CXX_FLAGS_INIT)
+
+set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,--gc-sections")
-set(CMAKE_CXX_FLAGS_INIT "-m64 -mno-red-zone -mcmodel=large -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections")
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3")
set(CMAKE_ASM_FLAGS_DEBUG "-ggdb3")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-ggdb3")
-set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-ggdb3")
-set(CMAKE_EXE_LINKER_FLAGS_INIT "-nostartfiles -Wl,--gc-sections")
-set(CMAKE_CXX_LINK_EXECUTABLE
- "<CMAKE_CXX_COMPILER> \
- <FLAGS> \
- <CMAKE_CXX_LINK_FLAGS> \
- <LINK_FLAGS> \
- ${CMAKE_SYSROOT}/crtbegin.o \
- <OBJECTS> \
- -o <TARGET> \
- <LINK_LIBRARIES> \
- -lgcc \
- ${CMAKE_SYSROOT}/crtend.o"
-)
+
+set(CMAKE_ASM_FLAGS_MINSIZEREL "-Os -DNDEBUG -ggdb3")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -ggdb3")
+
+set(CMAKE_ASM_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb3")
+set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb3")
+
+set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3")
diff --git a/docs/arch.rst b/docs/arch.rst
deleted file mode 100644
index 495d309..0000000
--- a/docs/arch.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Platform-Specific Infrastructure
-================================
-
-.. toctree::
- :maxdepth: 2
- :caption: Contents:
- :glob:
-
- arch/*
diff --git a/docs/briefs.rst b/docs/briefs.rst
new file mode 100644
index 0000000..1931345
--- /dev/null
+++ b/docs/briefs.rst
@@ -0,0 +1,9 @@
+Technical Briefs
+================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+ :glob:
+
+ briefs/*
diff --git a/docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst b/docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst
new file mode 100644
index 0000000..503ff43
--- /dev/null
+++ b/docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst
@@ -0,0 +1,161 @@
+Technical Brief 0001: Position-Independent Code (PIC) in 32-bit x86 Assembly for PIE Kernels
+============================================================================================
+
+The design of a modern x86-64 kernel, compiled as a Position-Independent Executable (PIE), necessitates a 32-bit assembly bootstrap stage for initial hardware setup.
+This architectural requirement, however, introduces significant challenges during the linking phase.
+A linker error may manifest during this process, presenting the following diagnostic:
+
+.. code-block:: text
+
+ relocation R_X86_64_32 against symbol `...' can not be used when making a PIE object; recompile with -fPIE
+
+This error arises despite the explicit use of the ``-fPIE`` compilation flag for the object file in question.
+Its occurrence indicates a fundamental incompatibility between the linking model of a PIE and the machine code generated from conventional 32-bit assembly instructions that reference symbolic addresses.
+This scenario reveals a critical distinction between compiler-generated position independence and the manual implementation required for hand-written assembly in a mixed-mode, relocatable binary.
+
+Root Cause Analysis
+-------------------
+
+The cause of this issue is a conflict between the linking model mandated by a Position-Independent Executable and the addressing capabilities inherent to the 32-bit x86 instruction set architecture (ISA).
+
+- **Position-Independent Executable (PIE) Constraints:**
+ A PIE is a variant of the Executable and Linkable Format (ELF) [#1]_ designed to be loaded at an arbitrary virtual address and function correctly without modification.
+ A strict prerequisite for this functionality is the complete absence of absolute virtual addresses within the binary's code and data sections.
+ Consequently, all internal data and function references must be encoded relative to the instruction pointer.
+ In the x86-64 ISA, this is typically accomplished through the native ``IP``-relative addressing mode (e.g., ``mov symbol(%rip), %rax``), which generates relocations of type ``R_X86_64_PC32``.
+ These PC-relative relocations are resolved by the linker based on the distance between the instruction and the symbol, a value that is constant regardless of the final load address.
+
+- **32-bit Addressing Limitations:**
+ The 32-bit x86 ISA lacks a native mechanism for instruction-pointer-relative addressing.
+ When an assembly instruction references a symbol by its name (e.g., ``movl $symbol, %eax``), the assembler's default behavior is to generate a relocation entry of type ``R_X86_64_32``.
+ This entry serves as a directive for the linker to substitute the symbol's final, 32-bit absolute virtual address into the machine code during the linking phase.
+ This process fundamentally embeds a hardcoded address into the instruction, making the code position-dependent.
+
+- **Mismatch:**
+ During the final link stage, the linker encounters these requests for absolute addresses within the 32-bit object code.
+ However, the linker's output target is a PIE, a format that explicitly forbids such absolute relocations because they would violate its defining characteristic of being relocatable.
+ The ``-fPIE`` flag, being a directive for a *compiler*, influences the code generation strategy for high-level languages like C++ but has no semantic effect on hand-written assembly that utilizes instructions which inherently produce absolute address relocations.
+ The linker, therefore, correctly identifies this violation of the PIE contract and terminates with an error.
+
+Solution: Runtime Address Calculation
+-------------------------------------
+
+Resolution of this conflict necessitates the manual implementation of position-independent code within the 32-bit assembly module.
+The core principle of this technique is the elimination of all instructions that would otherwise generate absolute address relocations.
+Instead, the absolute address of any required symbol must be calculated at runtime relative to the current instruction pointer.
+
+- **The ``call``/``pop`` Idiom:**
+ The canonical technique for obtaining the value of the 32-bit instruction pointer (``EIP``) involves a ``call`` to the immediately subsequent instruction.
+ The ``call`` instruction pushes its return address—which is the address of the next instruction—onto the stack.
+ A ``pop`` instruction can then retrieve this value into a general-purpose register.
+
+ .. code-block:: gas
+
+ call .Lget_eip
+ .Lget_eip:
+ popl %ebx
+
+ Upon completion of this sequence, the ``%ebx`` register contains the absolute virtual address of the ``.Lget_eip`` label at runtime.
+ This address serves as a reliable anchor from which other symbols' addresses can be calculated.
+
+- **Establishing a Base Register:**
+ By convention, specifically within the i386 System V ABI, the ``%ebx`` register is designated for this purpose.
+ It is classified as a "callee-saved" register, which obligates any conforming function to preserve its value across calls.
+ By establishing ``%ebx`` as a base register at the commencement of the bootstrap sequence, its value can be reliably utilized for all subsequent address calculations within that scope, even after calling external C or C++ functions.
+ Using a "caller-saved" register like ``%eax`` would be incorrect, as its value would have to be considered invalid after every function call.
+
+Representative Implementations
+------------------------------
+
+The subsequent examples provide canonical implementations for converting common position-dependent assembly instructions into their PIE-compliant equivalents.
+These examples assume that a base register, ``%ebx``, has been initialized with the current location counter via the ``call``/``pop`` idiom at a label which, for the purpose of these examples, is designated ``.Lbase``.
+
+Accessing a Symbol's Address
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This pattern is applicable when passing a pointer to a symbol as a function argument.
+
+- Problematic Code:
+
+ .. code-block:: gas
+
+ pushl $message_prefix_panic
+
+- PIE-Compatible Solution:
+
+ .. code-block:: gas
+
+ // Calculate the address: base_address + (symbol_address - base_address).
+ // The term (message_prefix_panic - .Lbase) is a link-time constant offset.
+ leal (message_prefix_panic - .Lbase)(%ebx), %eax
+ pushl %eax
+
+Accessing a Symbol's Content
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This pattern is employed when reading from or writing to a global variable.
+
+- Problematic Code:
+
+ .. code-block:: gas
+
+ movl (vga_buffer_pointer), %esi
+
+- PIE-Compatible Solution:
+
+ .. code-block:: gas
+
+ // First, calculate the address of the pointer variable into a register.
+ leal (vga_buffer_pointer - .Lbase)(%ebx), %edi
+ // Then, dereference the pointer via the register to access its content.
+ movl (%edi), %esi
+
+Complex Addressing Modes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This pattern is frequently used for array access.
+
+- Problematic Code:
+
+ .. code-block:: gas
+
+ movl %eax, page_map_level_2(,%ecx,8)
+
+- PIE-Compatible Solution:
+
+ .. code-block:: gas
+
+ // Calculate the base address of the array into a register.
+ leal (page_map_level_2 - .Lbase)(%ebx), %edx
+ // Utilize the register as the base in the complex addressing mode.
+ movl %eax, (%edx, %ecx, 8)
+
+Far Jumps
+~~~~~~~~~
+
+This technique is required for critical operations such as loading a new Global Descriptor Table (GDT) and transitioning to 64-bit mode.
+
+- Problematic Code:
+
+ .. code-block:: gas
+
+ jmp $global_descriptor_table_code, $_transition_to_long_mode
+
+- PIE-Compatible Solution (using ``lret``):
+
+ .. code-block:: gas
+
+ // Calculate the absolute virtual address of the 64-bit entry point.
+ leal (_transition_to_long_mode - .Lbase)(%ebx), %eax
+
+ // Push the new segment selector and the calculated address onto the stack.
+ pushl $global_descriptor_table_code
+ pushl %eax
+
+ // lret performs a far return, using the values from the stack,
+ // thereby achieving an indirect, position-independent far jump.
+ lret
+
+.. rubric:: References
+
+.. [#1] M. Matz, J. Hubička, A. Jaeger, and M. Mitchell, “System V Application Binary Interface AMD64 Architecture Processor Supplement Draft Version,” 2012. Available: https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf
diff --git a/docs/briefs/tb0002-x86_64_bootstrap.rst b/docs/briefs/tb0002-x86_64_bootstrap.rst
new file mode 100644
index 0000000..b7a6c2a
--- /dev/null
+++ b/docs/briefs/tb0002-x86_64_bootstrap.rst
@@ -0,0 +1,154 @@
+Technical Brief 0002: x86-64 Bootstrap Subsystem
+================================================
+
+System Requirements and Constraints
+-----------------------------------
+
+The design of a clean-slate, C++23-based operating system kernel necessitates a low-level bootstrap subsystem.
+This subsystem manages the transition from the machine's power-on state to a controlled 64-bit execution environment.
+It must operate under several architectural and toolchain constraints:
+
+1. **Bootloader Conformance:** The kernel is loaded by a bootloader adhering to the Multiboot2 Specification.
+ This conformance establishes a critical contract between the bootloader and the kernel.
+ The bootstrap code must therefore correctly identify the Multiboot2 magic number (``0x36d76289``) passed in the ``%eax`` register.
+ It must also interpret the pointer to the boot information structure passed in ``%ebx`` [1]_.
+ Adhering to this standard decouples the kernel from any specific bootloader implementation, ensuring portability across compliant environments like GRUB 2.
+
+2. **CPU Mode Transition:** The CPU is assumed to be in 32-bit protected mode upon entry to the bootstrap code.
+ The subsystem is responsible for all requisite steps to enable 64-bit long mode.
+ This is a non-trivial process.
+ It involves enabling Physical Address Extension (PAE) via the ``%cr4`` control register, setting the Long Mode Enable (LME) bit in the Extended Feature Enable Register (EFER) MSR (``0xC0000080``), and finally enabling paging via the ``%cr0`` control register.
+
+3. **Position-Independent Executable (PIE):** The kernel is compiled and linked as a PIE to allow it to be loaded at an arbitrary physical address.
+ This imposes a strict constraint on the 32-bit assembly code: it must not contain any absolute address relocations.
+ While a C++ compiler can generate position-independent code automatically, in hand-written assembly this requires the manual calculation of all symbol addresses at runtime.
+ This is a significant departure from simpler, absolute-addressed code.
+
+Architectural Overview
+----------------------
+
+The bootstrap architecture is partitioned into three distinct components.
+This enforces a modular and verifiable transition sequence.
+The components are: a shared C++/assembly interface (``boot.hpp``), a 32-bit PIE transition stage (``boot32.S``), and a minimal 64-bit entry stage (``entry64.s``).
+This separation is a deliberate design choice to manage complexity.
+It ensures that mode-specific logic is isolated, preventing subtle bugs that could arise from mixing 32-bit and 64-bit concerns.
+Furthermore, it makes the state transition between each stage explicit and auditable.
+This is critical for both debugging and for the educational utility of the codebase.
+
+Component Analysis
+------------------
+
+C++/Assembly Interface (``boot.hpp``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A single header file serves as the definitive interface between assembly code and C++.
+This is achieved through the use of the ``__ASSEMBLER__`` preprocessor macro.
+This is a standard feature of the GNU toolchain that allows a single file to serve a dual purpose.
+
+* **Shared Constants:** The header defines all magic numbers (e.g., ``MULTIBOOT2_MAGIC``), GDT flags, and other constants required by both the assembly and C++ code.
+ This ensures a single source of truth, eliminating the risk of inconsistencies that could arise from maintaining parallel definitions in different language domains.
+
+* **Conditional Declarations:** C++-specific declarations, such as ``extern "C"`` variable declarations using the ``teachos::arch::asm_pointer`` wrapper, are confined within an ``#ifndef __ASSEMBLER__`` block.
+ This prevents the assembler from attempting to parse C++ syntax—which would result in a compilation error—while making the full, type-safe interface available to the C++ compiler.
+ The ``asm_pointer`` class is particularly important.
+ It encapsulates a raw address and prevents its unsafe use as a standard pointer within C++, forcing any interaction to be explicit and controlled.
+
+32-bit Transition Stage (``boot32.S``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This file contains all code and data necessary to prepare the system for long mode.
+Its logic is fundamentally incompatible with the 64-bit environment due to differences in stack width, calling conventions, and instruction encoding.
+
+* **Position-Independent Execution (PIE):** The 32-bit x86 ISA lacks a native instruction-pointer-relative addressing mode.
+ To satisfy the PIE constraint, all symbol addresses are calculated at runtime.
+ This is achieved via the ``call/pop`` idiom to retrieve the value of the instruction pointer (``%eip``) into a base register (``%esi``).
+ All subsequent memory accesses are then performed by calculating a link-time constant offset from this runtime base (e.g., ``leal (symbol - .Lbase)(%esi), %eax``).
+ This manual implementation of position independence is critical to avoid linker errors related to absolute relocations (``R_X86_64_32``) in a PIE binary.
+
+* **System State Verification:** The first actions are a series of assertions.
+ The code first verifies the Multiboot2 magic number (``0x36d76289``) passed in ``%eax`` [1]_.
+ It then uses the ``CPUID`` instruction to verify that the processor supports long mode.
+ This is done by checking for the LM bit (bit 29) in ``%edx`` after executing ``CPUID`` with ``0x80000001`` in ``%eax`` [2]_.
+ Failure of any assertion results in a call to a panic routine that halts the system.
+ This "fail-fast" approach is crucial; proceeding in an unsupported environment would lead to unpredictable and difficult-to-debug faults deep within the kernel.
+
+* **Formal Transition via ``lret``:** The stage concludes with a ``lret`` (long return) instruction.
+ This is the architecturally mandated method for performing an inter-segment control transfer.
+ This is required to load a new code segment selector and change the CPU's execution mode.
+ A simple ``jmp`` is insufficient as it cannot change the execution mode.
+ The choice of ``lret`` over other far-control transfer instructions like ``ljmp`` or ``lcall`` is a direct consequence of the PIE constraint.
+ The direct forms of ``ljmp`` and ``lcall`` require their target address to be a link-time constant.
+ This would embed an absolute address into the executable and violate the principles of position independence.
+ In contrast, ``lret`` consumes its target selector and offset from the stack.
+ This mechanism is perfectly suited for a PIE environment.
+ It allows for a dynamically calculated, position-independent address to be pushed onto the stack immediately before the instruction is executed.
+ Furthermore, ``lcall`` is architecturally inappropriate.
+ It would push a 32-bit return address onto the stack before the mode switch, corrupting the 64-bit stack frame for a transition that should be strictly one-way.
+ ``lret`` correctly models this one-way transfer and is therefore the only viable and clean option.
+
+64-bit Entry Stage (``entry64.s``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This file provides a minimal, clean entry point into the 64-bit world.
+It ensures the C++ kernel begins execution in a pristine environment.
+
+* **Final State Setup:** Its sole responsibilities are to initialize the 64-bit data segment registers (``%ss``, ``%ds``, etc.) with the correct selector from the new GDT.
+ It then transfers control to the C++ kernel's ``main`` function via a standard ``call``.
+ Setting the segment registers is the first action performed.
+ Any memory access in 64-bit mode—including the stack operations performed by the subsequent ``call``—depends on these selectors being valid.
+ Failure to do so would result in a general protection fault.
+
+* **Halt State:** Should ``main`` ever return—an event that signifies a critical kernel failure—execution falls through to an infinite ``hlt`` loop.
+ This is a crucial fail-safe.
+ It prevents the CPU from executing beyond the end of the kernel's code, which would lead to unpredictable behavior as the CPU attempts to interpret non-executable data as instructions.
+
+Key Implementation Decisions
+----------------------------
+
+``lret`` Stack Frame Construction
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The transition to 64-bit mode is initiated by executing an ``lret`` instruction from 32-bit protected mode.
+The behavior of this instruction is determined by the characteristics of the destination code segment descriptor referenced by the selector on the stack.
+
+The stack is prepared as follows:
+
+1. ``leal (_entry64 - .Lbase)(%esi), %eax``: The PIE-compatible virtual address of the 64-bit entry point is calculated and placed in ``%eax``.
+
+2. ``pushl $global_descriptor_table_code``: The 16-bit selector for the 64-bit code segment is pushed onto the stack as a 32-bit value.
+
+3. ``pushl %eax``: The 32-bit address of the entry point is pushed onto the stack.
+
+When ``lret`` is executed in 32-bit mode, it pops a 32-bit instruction pointer and a 16-bit code selector from the stack [3]_.
+The processor then examines the GDT descriptor referenced by the new code selector.
+Because this descriptor has its L-bit (Long Mode) set to 1, the processor transitions into 64-bit long mode.
+It then begins executing at the 64-bit address specified by the popped instruction pointer [2]_.
+
+Memory Virtualization and GDT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A four-level page table hierarchy (PML4) is constructed to enable paging, a prerequisite for long mode.
+An initial identity map of 32 MiB of physical memory is created using 2 MiB huge pages.
+This reduces the number of required page table entries for the initial kernel image.
+A recursive mapping in the PML4 at a conventional index (511) is also established.
+This powerful technique allows the C++ kernel's memory manager to access and modify the entire page table hierarchy as if it were a linear array at a single, well-known virtual address.
+This greatly simplifies the logic required for virtual memory operations.
+
+A new GDT is defined containing the necessary null, 64-bit code, and 64-bit data descriptors.
+The first entry in the GDT must be a null descriptor, as the processor architecture reserves selector value 0 as a special "null selector."
+Loading a segment register with this null selector is valid.
+However, any subsequent memory access using it (with the exception of CS or SS) will generate a general-protection exception.
+This provides a fail-safe mechanism against the use of uninitialized segment selectors [2]_.
+The selector for the data descriptor is exported as a global symbol (``global_descriptor_table_data``).
+This design choice was made to prioritize explicitness and debuggability.
+The dependency is clearly visible in the source code, over the alternative of passing the selector value in a register.
+This would create an implicit, less obvious contract between the two stages that could complicate future maintenance.
+
+References
+----------
+
+.. [1] Free Software Foundation, "The Multiboot2 Specification, version 2.0," Free Software Foundation, Inc., 2016. `Online <https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html>`_.
+
+.. [2] Intel Corporation, *Intel® 64 and IA-32 Architectures Software Developer’s Manual, Combined Volumes 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D and 4*, Order No. 325462-081US, July 2025. `Online <https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html>`_.
+
+.. [3] AMD, Inc., *AMD64 Architecture Programmer’s Manual, Volume 3: General-Purpose and System Instructions*, Publication No. 24594, Rev. 3.42, June 2025. `Online <https://www.amd.com/en/support/tech-docs/amd64-architecture-programmers-manual-volumes-1-5>`_.
diff --git a/docs/conf.py b/docs/conf.py
index 90ed3dc..b8cfe69 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,16 +13,16 @@ author = "Felix Morgner"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
-extensions = ["breathe"]
+#extensions = ["breathe"]
templates_path = ["_templates"]
-exclude_patterns = []
+exclude_patterns = ["pre/**"]
# -- Options Breathe ---------------------------------------------------------
# https://breathe.readthedocs.io/en/stable/directives.html#config-values
-breathe_projects = {"kernel": "../build/doxygen/xml"}
-breathe_default_project = "kernel"
+#breathe_projects = {"kernel": "../build/doxygen/xml"}
+#breathe_default_project = "kernel"
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
diff --git a/docs/cross.rst b/docs/cross.rst
deleted file mode 100644
index 542d76a..0000000
--- a/docs/cross.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Platform-Independent Infrastructure
-===================================
-
-.. toctree::
- :maxdepth: 2
- :caption: Contents:
- :glob:
-
- cross/*
diff --git a/docs/index.rst b/docs/index.rst
index e3a749f..649e6de 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -5,8 +5,7 @@ Welcome to TeachOS Kernel's documentation!
:maxdepth: 2
:caption: Contents:
- arch
- cross
+ briefs
Indices and tables
==================
diff --git a/docs/arch/x86_64.rst b/docs/pre/arch/x86_64.rst
index dc432f1..dc432f1 100644
--- a/docs/arch/x86_64.rst
+++ b/docs/pre/arch/x86_64.rst
diff --git a/docs/arch/x86_64/boot.rst b/docs/pre/arch/x86_64/boot.rst
index 8be2a57..8be2a57 100644
--- a/docs/arch/x86_64/boot.rst
+++ b/docs/pre/arch/x86_64/boot.rst
diff --git a/docs/arch/x86_64/boot/pointers.rst b/docs/pre/arch/x86_64/boot/pointers.rst
index 3ec626a..3ec626a 100644
--- a/docs/arch/x86_64/boot/pointers.rst
+++ b/docs/pre/arch/x86_64/boot/pointers.rst
diff --git a/docs/arch/x86_64/context_switching.rst b/docs/pre/arch/x86_64/context_switching.rst
index c3b3b03..c3b3b03 100644
--- a/docs/arch/x86_64/context_switching.rst
+++ b/docs/pre/arch/x86_64/context_switching.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst
index dd6e478..dd6e478 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst
index 29e7586..29e7586 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst
index 60e8c37..60e8c37 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst
index a2b8997..a2b8997 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst
index 3a8c259..3a8c259 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst
index ddba6ee..ddba6ee 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst
diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst
index 2da142e..2da142e 100644
--- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst
+++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst
diff --git a/docs/arch/x86_64/context_switching/main.rst b/docs/pre/arch/x86_64/context_switching/main.rst
index e9e8a35..e9e8a35 100644
--- a/docs/arch/x86_64/context_switching/main.rst
+++ b/docs/pre/arch/x86_64/context_switching/main.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst
index 449622d..449622d 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst
index f2e7d67..f2e7d67 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst
index faa2ffc..faa2ffc 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst
index 35403db..35403db 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst
index 41ceffd..41ceffd 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst
index 952ab2a..952ab2a 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst
index 874d1cb..874d1cb 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst
index e45b0a5..e45b0a5 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst
diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst
index 731d7bb..731d7bb 100644
--- a/docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst
+++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst
diff --git a/docs/arch/x86_64/context_switching/syscall.rst b/docs/pre/arch/x86_64/context_switching/syscall.rst
index 28acf28..28acf28 100644
--- a/docs/arch/x86_64/context_switching/syscall.rst
+++ b/docs/pre/arch/x86_64/context_switching/syscall.rst
diff --git a/docs/arch/x86_64/context_switching/syscall/main.rst b/docs/pre/arch/x86_64/context_switching/syscall/main.rst
index 6be577b..6be577b 100644
--- a/docs/arch/x86_64/context_switching/syscall/main.rst
+++ b/docs/pre/arch/x86_64/context_switching/syscall/main.rst
diff --git a/docs/arch/x86_64/context_switching/syscall/syscall_enable.rst b/docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst
index e9162f1..e9162f1 100644
--- a/docs/arch/x86_64/context_switching/syscall/syscall_enable.rst
+++ b/docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst
diff --git a/docs/arch/x86_64/context_switching/syscall/syscall_handler.rst b/docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst
index 0e86780..0e86780 100644
--- a/docs/arch/x86_64/context_switching/syscall/syscall_handler.rst
+++ b/docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst
diff --git a/docs/arch/x86_64/exception_handling.rst b/docs/pre/arch/x86_64/exception_handling.rst
index 3bf2770..3bf2770 100644
--- a/docs/arch/x86_64/exception_handling.rst
+++ b/docs/pre/arch/x86_64/exception_handling.rst
diff --git a/docs/arch/x86_64/exception_handling/assert.rst b/docs/pre/arch/x86_64/exception_handling/assert.rst
index 053cf66..053cf66 100644
--- a/docs/arch/x86_64/exception_handling/assert.rst
+++ b/docs/pre/arch/x86_64/exception_handling/assert.rst
diff --git a/docs/arch/x86_64/exception_handling/panic.rst b/docs/pre/arch/x86_64/exception_handling/panic.rst
index 50b6284..50b6284 100644
--- a/docs/arch/x86_64/exception_handling/panic.rst
+++ b/docs/pre/arch/x86_64/exception_handling/panic.rst
diff --git a/docs/arch/x86_64/interrupt_handling.rst b/docs/pre/arch/x86_64/interrupt_handling.rst
index d4ff94a..d4ff94a 100644
--- a/docs/arch/x86_64/interrupt_handling.rst
+++ b/docs/pre/arch/x86_64/interrupt_handling.rst
diff --git a/docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst b/docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst
index 6099170..6099170 100644
--- a/docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst
+++ b/docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst
diff --git a/docs/arch/x86_64/io.rst b/docs/pre/arch/x86_64/io.rst
index 7082bd5..7082bd5 100644
--- a/docs/arch/x86_64/io.rst
+++ b/docs/pre/arch/x86_64/io.rst
diff --git a/docs/arch/x86_64/io/port_io.rst b/docs/pre/arch/x86_64/io/port_io.rst
index 18a9f6a..18a9f6a 100644
--- a/docs/arch/x86_64/io/port_io.rst
+++ b/docs/pre/arch/x86_64/io/port_io.rst
diff --git a/docs/arch/x86_64/kernel.rst b/docs/pre/arch/x86_64/kernel.rst
index 650e3a6..650e3a6 100644
--- a/docs/arch/x86_64/kernel.rst
+++ b/docs/pre/arch/x86_64/kernel.rst
diff --git a/docs/arch/x86_64/kernel/cpu.rst b/docs/pre/arch/x86_64/kernel/cpu.rst
index da3dfc0..da3dfc0 100644
--- a/docs/arch/x86_64/kernel/cpu.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu.rst
diff --git a/docs/arch/x86_64/kernel/cpu/call.rst b/docs/pre/arch/x86_64/kernel/cpu/call.rst
index 33d15ec..33d15ec 100644
--- a/docs/arch/x86_64/kernel/cpu/call.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/call.rst
diff --git a/docs/arch/x86_64/kernel/cpu/control_register.rst b/docs/pre/arch/x86_64/kernel/cpu/control_register.rst
index a45c6d9..a45c6d9 100644
--- a/docs/arch/x86_64/kernel/cpu/control_register.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/control_register.rst
diff --git a/docs/arch/x86_64/kernel/cpu/gdtr.rst b/docs/pre/arch/x86_64/kernel/cpu/gdtr.rst
index 41c0f6b..41c0f6b 100644
--- a/docs/arch/x86_64/kernel/cpu/gdtr.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/gdtr.rst
diff --git a/docs/arch/x86_64/kernel/cpu/idtr.rst b/docs/pre/arch/x86_64/kernel/cpu/idtr.rst
index b4c4bb0..b4c4bb0 100644
--- a/docs/arch/x86_64/kernel/cpu/idtr.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/idtr.rst
diff --git a/docs/arch/x86_64/kernel/cpu/if.rst b/docs/pre/arch/x86_64/kernel/cpu/if.rst
index 2dd07b4..2dd07b4 100644
--- a/docs/arch/x86_64/kernel/cpu/if.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/if.rst
diff --git a/docs/arch/x86_64/kernel/cpu/msr.rst b/docs/pre/arch/x86_64/kernel/cpu/msr.rst
index 75c4f47..75c4f47 100644
--- a/docs/arch/x86_64/kernel/cpu/msr.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/msr.rst
diff --git a/docs/arch/x86_64/kernel/cpu/segment_register.rst b/docs/pre/arch/x86_64/kernel/cpu/segment_register.rst
index 8159369..8159369 100644
--- a/docs/arch/x86_64/kernel/cpu/segment_register.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/segment_register.rst
diff --git a/docs/arch/x86_64/kernel/cpu/tlb.rst b/docs/pre/arch/x86_64/kernel/cpu/tlb.rst
index 1ceec1d..1ceec1d 100644
--- a/docs/arch/x86_64/kernel/cpu/tlb.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/tlb.rst
diff --git a/docs/arch/x86_64/kernel/cpu/tr.rst b/docs/pre/arch/x86_64/kernel/cpu/tr.rst
index a2b234b..a2b234b 100644
--- a/docs/arch/x86_64/kernel/cpu/tr.rst
+++ b/docs/pre/arch/x86_64/kernel/cpu/tr.rst
diff --git a/docs/arch/x86_64/kernel/halt.rst b/docs/pre/arch/x86_64/kernel/halt.rst
index c425e81..c425e81 100644
--- a/docs/arch/x86_64/kernel/halt.rst
+++ b/docs/pre/arch/x86_64/kernel/halt.rst
diff --git a/docs/arch/x86_64/kernel/main.rst b/docs/pre/arch/x86_64/kernel/main.rst
index 194bd85..194bd85 100644
--- a/docs/arch/x86_64/kernel/main.rst
+++ b/docs/pre/arch/x86_64/kernel/main.rst
diff --git a/docs/arch/x86_64/memory.rst b/docs/pre/arch/x86_64/memory.rst
index 58d12e9..58d12e9 100644
--- a/docs/arch/x86_64/memory.rst
+++ b/docs/pre/arch/x86_64/memory.rst
diff --git a/docs/arch/x86_64/memory/allocator.rst b/docs/pre/arch/x86_64/memory/allocator.rst
index 6ce0a74..6ce0a74 100644
--- a/docs/arch/x86_64/memory/allocator.rst
+++ b/docs/pre/arch/x86_64/memory/allocator.rst
diff --git a/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst b/docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst
index 422f33c..422f33c 100644
--- a/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst
diff --git a/docs/arch/x86_64/memory/allocator/concept.rst b/docs/pre/arch/x86_64/memory/allocator/concept.rst
index 734a2ce..734a2ce 100644
--- a/docs/arch/x86_64/memory/allocator/concept.rst
+++ b/docs/pre/arch/x86_64/memory/allocator/concept.rst
diff --git a/docs/arch/x86_64/memory/allocator/physical_frame.rst b/docs/pre/arch/x86_64/memory/allocator/physical_frame.rst
index c5d0fd2..c5d0fd2 100644
--- a/docs/arch/x86_64/memory/allocator/physical_frame.rst
+++ b/docs/pre/arch/x86_64/memory/allocator/physical_frame.rst
diff --git a/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst b/docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst
index 27401b2..27401b2 100644
--- a/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst
diff --git a/docs/arch/x86_64/memory/cpu.rst b/docs/pre/arch/x86_64/memory/cpu.rst
index 4cb5af0..4cb5af0 100644
--- a/docs/arch/x86_64/memory/cpu.rst
+++ b/docs/pre/arch/x86_64/memory/cpu.rst
diff --git a/docs/arch/x86_64/memory/heap.rst b/docs/pre/arch/x86_64/memory/heap.rst
index 409d93a..409d93a 100644
--- a/docs/arch/x86_64/memory/heap.rst
+++ b/docs/pre/arch/x86_64/memory/heap.rst
diff --git a/docs/arch/x86_64/memory/heap/bump_allocator.rst b/docs/pre/arch/x86_64/memory/heap/bump_allocator.rst
index b20916e..b20916e 100644
--- a/docs/arch/x86_64/memory/heap/bump_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/heap/bump_allocator.rst
diff --git a/docs/arch/x86_64/memory/heap/global_heap_allocator.rst b/docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst
index 60ec0b5..60ec0b5 100644
--- a/docs/arch/x86_64/memory/heap/global_heap_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst
diff --git a/docs/arch/x86_64/memory/heap/heap_allocator.rst b/docs/pre/arch/x86_64/memory/heap/heap_allocator.rst
index b410e41..b410e41 100644
--- a/docs/arch/x86_64/memory/heap/heap_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/heap/heap_allocator.rst
diff --git a/docs/arch/x86_64/memory/heap/linked_list_allocator.rst b/docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst
index d156852..d156852 100644
--- a/docs/arch/x86_64/memory/heap/linked_list_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst
diff --git a/docs/arch/x86_64/memory/heap/memory_block.rst b/docs/pre/arch/x86_64/memory/heap/memory_block.rst
index 8ed6566..8ed6566 100644
--- a/docs/arch/x86_64/memory/heap/memory_block.rst
+++ b/docs/pre/arch/x86_64/memory/heap/memory_block.rst
diff --git a/docs/arch/x86_64/memory/heap/user_heap_allocator.rst b/docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst
index d0febb6..d0febb6 100644
--- a/docs/arch/x86_64/memory/heap/user_heap_allocator.rst
+++ b/docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst
diff --git a/docs/arch/x86_64/memory/main.rst b/docs/pre/arch/x86_64/memory/main.rst
index d9a9f39..d9a9f39 100644
--- a/docs/arch/x86_64/memory/main.rst
+++ b/docs/pre/arch/x86_64/memory/main.rst
diff --git a/docs/arch/x86_64/memory/multiboot.rst b/docs/pre/arch/x86_64/memory/multiboot.rst
index 22ec3f2..22ec3f2 100644
--- a/docs/arch/x86_64/memory/multiboot.rst
+++ b/docs/pre/arch/x86_64/memory/multiboot.rst
diff --git a/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst b/docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst
index bbd6dfb..bbd6dfb 100644
--- a/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst
+++ b/docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst
diff --git a/docs/arch/x86_64/memory/multiboot/info.rst b/docs/pre/arch/x86_64/memory/multiboot/info.rst
index 847870d..847870d 100644
--- a/docs/arch/x86_64/memory/multiboot/info.rst
+++ b/docs/pre/arch/x86_64/memory/multiboot/info.rst
diff --git a/docs/arch/x86_64/memory/multiboot/memory_map.rst b/docs/pre/arch/x86_64/memory/multiboot/memory_map.rst
index 9c77331..9c77331 100644
--- a/docs/arch/x86_64/memory/multiboot/memory_map.rst
+++ b/docs/pre/arch/x86_64/memory/multiboot/memory_map.rst
diff --git a/docs/arch/x86_64/memory/multiboot/reader.rst b/docs/pre/arch/x86_64/memory/multiboot/reader.rst
index fac98e2..fac98e2 100644
--- a/docs/arch/x86_64/memory/multiboot/reader.rst
+++ b/docs/pre/arch/x86_64/memory/multiboot/reader.rst
diff --git a/docs/arch/x86_64/memory/paging.rst b/docs/pre/arch/x86_64/memory/paging.rst
index 10cd976..10cd976 100644
--- a/docs/arch/x86_64/memory/paging.rst
+++ b/docs/pre/arch/x86_64/memory/paging.rst
diff --git a/docs/arch/x86_64/memory/paging/active_page_table.rst b/docs/pre/arch/x86_64/memory/paging/active_page_table.rst
index 5710131..5710131 100644
--- a/docs/arch/x86_64/memory/paging/active_page_table.rst
+++ b/docs/pre/arch/x86_64/memory/paging/active_page_table.rst
diff --git a/docs/arch/x86_64/memory/paging/inactive_page_table.rst b/docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst
index 5732e64..5732e64 100644
--- a/docs/arch/x86_64/memory/paging/inactive_page_table.rst
+++ b/docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst
diff --git a/docs/arch/x86_64/memory/paging/kernel_mapper.rst b/docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst
index 9948e4e..9948e4e 100644
--- a/docs/arch/x86_64/memory/paging/kernel_mapper.rst
+++ b/docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst
diff --git a/docs/arch/x86_64/memory/paging/page_entry.rst b/docs/pre/arch/x86_64/memory/paging/page_entry.rst
index 8900b0e..8900b0e 100644
--- a/docs/arch/x86_64/memory/paging/page_entry.rst
+++ b/docs/pre/arch/x86_64/memory/paging/page_entry.rst
diff --git a/docs/arch/x86_64/memory/paging/page_table.rst b/docs/pre/arch/x86_64/memory/paging/page_table.rst
index c5ab8c7..c5ab8c7 100644
--- a/docs/arch/x86_64/memory/paging/page_table.rst
+++ b/docs/pre/arch/x86_64/memory/paging/page_table.rst
diff --git a/docs/arch/x86_64/memory/paging/temporary_page.rst b/docs/pre/arch/x86_64/memory/paging/temporary_page.rst
index 0c63899..0c63899 100644
--- a/docs/arch/x86_64/memory/paging/temporary_page.rst
+++ b/docs/pre/arch/x86_64/memory/paging/temporary_page.rst
diff --git a/docs/arch/x86_64/memory/paging/virtual_page.rst b/docs/pre/arch/x86_64/memory/paging/virtual_page.rst
index dd42f47..dd42f47 100644
--- a/docs/arch/x86_64/memory/paging/virtual_page.rst
+++ b/docs/pre/arch/x86_64/memory/paging/virtual_page.rst
diff --git a/docs/arch/x86_64/stl.rst b/docs/pre/arch/x86_64/stl.rst
index bb21f9a..bb21f9a 100644
--- a/docs/arch/x86_64/stl.rst
+++ b/docs/pre/arch/x86_64/stl.rst
diff --git a/docs/arch/x86_64/stl/container.rst b/docs/pre/arch/x86_64/stl/container.rst
index 19c735b..19c735b 100644
--- a/docs/arch/x86_64/stl/container.rst
+++ b/docs/pre/arch/x86_64/stl/container.rst
diff --git a/docs/arch/x86_64/stl/contiguous_pointer_iterator.rst b/docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst
index 47f88c4..47f88c4 100644
--- a/docs/arch/x86_64/stl/contiguous_pointer_iterator.rst
+++ b/docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst
diff --git a/docs/arch/x86_64/stl/forward_value_iterator.rst b/docs/pre/arch/x86_64/stl/forward_value_iterator.rst
index 72270de..72270de 100644
--- a/docs/arch/x86_64/stl/forward_value_iterator.rst
+++ b/docs/pre/arch/x86_64/stl/forward_value_iterator.rst
diff --git a/docs/arch/x86_64/stl/mutex.rst b/docs/pre/arch/x86_64/stl/mutex.rst
index 2098113..2098113 100644
--- a/docs/arch/x86_64/stl/mutex.rst
+++ b/docs/pre/arch/x86_64/stl/mutex.rst
diff --git a/docs/arch/x86_64/stl/shared_pointer.rst b/docs/pre/arch/x86_64/stl/shared_pointer.rst
index 46ddb65..46ddb65 100644
--- a/docs/arch/x86_64/stl/shared_pointer.rst
+++ b/docs/pre/arch/x86_64/stl/shared_pointer.rst
diff --git a/docs/arch/x86_64/stl/stack.rst b/docs/pre/arch/x86_64/stl/stack.rst
index a554387..a554387 100644
--- a/docs/arch/x86_64/stl/stack.rst
+++ b/docs/pre/arch/x86_64/stl/stack.rst
diff --git a/docs/arch/x86_64/stl/unique_pointer.rst b/docs/pre/arch/x86_64/stl/unique_pointer.rst
index f508763..f508763 100644
--- a/docs/arch/x86_64/stl/unique_pointer.rst
+++ b/docs/pre/arch/x86_64/stl/unique_pointer.rst
diff --git a/docs/arch/x86_64/stl/vector.rst b/docs/pre/arch/x86_64/stl/vector.rst
index b60023a..b60023a 100644
--- a/docs/arch/x86_64/stl/vector.rst
+++ b/docs/pre/arch/x86_64/stl/vector.rst
diff --git a/docs/arch/x86_64/user.rst b/docs/pre/arch/x86_64/user.rst
index 3be32bb..3be32bb 100644
--- a/docs/arch/x86_64/user.rst
+++ b/docs/pre/arch/x86_64/user.rst
diff --git a/docs/arch/x86_64/user/main.rst b/docs/pre/arch/x86_64/user/main.rst
index 0f641b2..0f641b2 100644
--- a/docs/arch/x86_64/user/main.rst
+++ b/docs/pre/arch/x86_64/user/main.rst
diff --git a/docs/arch/x86_64/video.rst b/docs/pre/arch/x86_64/video.rst
index bbae5ed..bbae5ed 100644
--- a/docs/arch/x86_64/video.rst
+++ b/docs/pre/arch/x86_64/video.rst
diff --git a/docs/arch/x86_64/video/vga.rst b/docs/pre/arch/x86_64/video/vga.rst
index 2c32bb2..2c32bb2 100644
--- a/docs/arch/x86_64/video/vga.rst
+++ b/docs/pre/arch/x86_64/video/vga.rst
diff --git a/docs/arch/x86_64/video/vga/io.rst b/docs/pre/arch/x86_64/video/vga/io.rst
index 39609c9..39609c9 100644
--- a/docs/arch/x86_64/video/vga/io.rst
+++ b/docs/pre/arch/x86_64/video/vga/io.rst
diff --git a/docs/arch/x86_64/video/vga/text.rst b/docs/pre/arch/x86_64/video/vga/text.rst
index 592cdd5..592cdd5 100644
--- a/docs/arch/x86_64/video/vga/text.rst
+++ b/docs/pre/arch/x86_64/video/vga/text.rst
diff --git a/docs/cross/memory.rst b/docs/pre/cross/memory.rst
index 3a2c1c4..3a2c1c4 100644
--- a/docs/cross/memory.rst
+++ b/docs/pre/cross/memory.rst
diff --git a/docs/cross/memory/asm_pointer.rst b/docs/pre/cross/memory/asm_pointer.rst
index 70f5c01..70f5c01 100644
--- a/docs/cross/memory/asm_pointer.rst
+++ b/docs/pre/cross/memory/asm_pointer.rst
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..733e873
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,2 @@
+Sphinx~=8.2.0
+sphinx_book_theme~=1.1.0
diff --git a/include/memory/asm_pointer.hpp b/include/memory/asm_pointer.hpp
deleted file mode 100644
index 4c25658..0000000
--- a/include/memory/asm_pointer.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef TEACHOS_MEMORY_ASM_POINTER_HPP
-#define TEACHOS_MEMORY_ASM_POINTER_HPP
-
-namespace teachos::memory
-{
-
- /**
- * @brief A pointer that is defined in some assembly source file.
- *
- * @tparam Type The type of the pointer
- * @since 0.0.1
- */
- template<typename Type>
- struct asm_pointer
- {
- /**
- * @brief The type of the underlying pointer.
- */
- using pointer = Type *;
-
- /**
- * @brief Construct a new asm_pointer for a given assembly-defined pointer.
- *
- * @param pointer A pointer defined in assembly.
- */
- constexpr asm_pointer(Type *& pointer)
- : m_pointer{&pointer}
- {
- // Nothing to do
- }
-
- /**
- * @brief Access the underlying pointer.
- *
- * @return The pointer wrapped by this asm_pointer.
- */
- auto constexpr operator*() -> pointer & { return *m_pointer; }
-
- /**
- * @brief Access the underlying pointer.
- *
- * @return The pointer wrapped by this asm_pointer.
- */
- auto constexpr operator*() const -> pointer const & { return *m_pointer; }
-
- private:
- pointer * m_pointer;
- };
-
- /**
- * @copydoc asm_pointer
- *
- * @note This specialization allows the use of this type for pointers to constant data.
- * @since 0.0.1
- */
- template<typename Type>
- struct asm_pointer<Type const>
- {
- /** @copydoc asm_pointer<Type>::asm_pointer */
- constexpr asm_pointer(Type const & pointer)
- : m_pointer{&pointer}
- {
- }
-
- /** @copydoc asm_pointer<Type>::operator*() */
- auto constexpr operator*() -> Type const & { return *m_pointer; }
- /** @copydoc asm_pointer<Type>::operator*() const */
- auto constexpr operator*() const -> Type const & { return *m_pointer; }
-
- private:
- Type const * m_pointer;
- };
-
-} // namespace teachos::memory
-
-#endif // TEACHOS_MEMORY_ASM_POINTER_HPP
diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt
new file mode 100644
index 0000000..5e914bb
--- /dev/null
+++ b/kapi/CMakeLists.txt
@@ -0,0 +1,34 @@
+add_library("kapi" INTERFACE)
+add_library("os::kapi" ALIAS "kapi")
+
+target_sources("kapi" PUBLIC
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ "include/kapi/boot.hpp"
+ "include/kapi/cio.hpp"
+ "include/kapi/memory.hpp"
+ "include/kapi/memory/address.hpp"
+ "include/kapi/memory/frame_allocator.hpp"
+ "include/kapi/memory/frame.hpp"
+ "include/kapi/memory/page_mapper.hpp"
+ "include/kapi/memory/page.hpp"
+ "include/kapi/system.hpp"
+)
+
+target_include_directories("kapi" INTERFACE
+ "include"
+)
+
+target_link_libraries("kapi" INTERFACE
+ "libs::kstd"
+
+ "gcc"
+ "stdc++"
+)
+
+target_compile_definitions("kapi" INTERFACE
+ "PLATFORM_PAGE_SIZE=${TEACHOS_PLATFORM_PAGE_SIZE}uz"
+ "PLATFORM_PAGING_LEVELS=${TEACHOS_PLATFORM_PAGING_LEVELS}uz"
+ "PLATFORM_FRAME_SIZE=${TEACHOS_PLATFORM_FRAME_SIZE}uz"
+)
diff --git a/kapi/include/kapi/boot.hpp b/kapi/include/kapi/boot.hpp
new file mode 100644
index 0000000..9c344cf
--- /dev/null
+++ b/kapi/include/kapi/boot.hpp
@@ -0,0 +1,17 @@
+#ifndef TEACHOS_KAPI_BOOT_HPP
+#define TEACHOS_KAPI_BOOT_HPP
+
+namespace teachos::boot
+{
+ //! @qualifier platform-defined
+ //! Information passed from the early pre-main stage to the kernel executable.
+ //!
+ //! The specific structure of this type is defined on a platform level.
+ struct information;
+
+ //! @qualifier platform-defined
+ //! An object passed from the early pre-main stage to the kernel executable.
+ extern "C" information const bootstrap_information;
+} // namespace teachos::boot
+
+#endif
diff --git a/kapi/include/kapi/cio.hpp b/kapi/include/kapi/cio.hpp
new file mode 100644
index 0000000..071e6cb
--- /dev/null
+++ b/kapi/include/kapi/cio.hpp
@@ -0,0 +1,51 @@
+#ifndef TEACHOS_KAPI_CIO_HPP
+#define TEACHOS_KAPI_CIO_HPP
+
+#include "kapi/cio/output_device.hpp" // IWYU pragma: export
+
+#include <optional>
+#include <string_view>
+
+namespace teachos::cio
+{
+
+ //! @qualifier platform-defined
+ //! Initialize the character I/O subsystem.
+ //!
+ //! @note If a platform support character output, it shall ensure that when this function returns, basic character
+ //! output can be performed on the system.
+ auto init() -> void;
+
+ //! @qualifier kernel-defined
+ //! Set the currently active output device.
+ //!
+ //! @param device A new output device.
+ //! @return The previously active output device.
+ auto set_output_device(output_device & device) -> std::optional<output_device *>;
+
+ //! @qualifier kernel-defined
+ //! Print the given text to the currently active output device.
+ //!
+ //! @param text The text to print.
+ auto print(std::string_view text) -> void;
+
+ //! @qualifier kernel-defined
+ //! Print the given text, including a newline, to the currently active output device.
+ //!
+ //! @param text The text to print.
+ auto println(std::string_view text) -> void;
+
+ //! @qualifier kernel-defined
+ //! Print the given error text, to the currently active output device.
+ //!
+ //! @param text The error text to print.
+ auto print_error(std::string_view text) -> void;
+
+ //! @qualifier kernel-defined
+ //! Print the given error text, including a newline, to the currently active output device.
+ //!
+ //! @param text The error text to print.
+ auto println_error(std::string_view text) -> void;
+} // namespace teachos::cio
+
+#endif
diff --git a/kapi/include/kapi/cio/output_device.hpp b/kapi/include/kapi/cio/output_device.hpp
new file mode 100644
index 0000000..0599906
--- /dev/null
+++ b/kapi/include/kapi/cio/output_device.hpp
@@ -0,0 +1,47 @@
+#ifndef TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP
+#define TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP
+
+// IWYU pragma: private, include "kapi/cio.hpp"
+
+#include <string_view>
+
+namespace teachos::cio
+{
+
+ //! The interface of a device able to perform character output on a platform.
+ struct output_device
+ {
+ output_device(output_device const &) = delete;
+ output_device(output_device &&) = delete;
+ auto operator=(output_device const &) -> output_device & = delete;
+ auto operator=(output_device &&) -> output_device & = delete;
+
+ virtual ~output_device() = default;
+
+ //! Write the given text to the output device.
+ //!
+ //! @param text The text to write.
+ auto virtual write(std::string_view text) -> void = 0;
+
+ //! Write the given text to the output device, appending a newline
+ //!
+ //! @param text The text to write.
+ auto virtual writeln(std::string_view text) -> void = 0;
+
+ //! Write the given error text to the output device.
+ //!
+ //! @param text The text to write.
+ auto virtual write_error(std::string_view text) -> void = 0;
+
+ //! Write the given error text to the output device, appending a newline
+ //!
+ //! @param text The text to write.
+ auto virtual writeln_error(std::string_view text) -> void = 0;
+
+ protected:
+ output_device() = default;
+ };
+
+} // namespace teachos::cio
+
+#endif
diff --git a/kapi/include/kapi/cpu.hpp b/kapi/include/kapi/cpu.hpp
new file mode 100644
index 0000000..0a26bcf
--- /dev/null
+++ b/kapi/include/kapi/cpu.hpp
@@ -0,0 +1,13 @@
+#ifndef TEACHOS_KAPI_CPU_HPP
+#define TEACHOS_KAPI_CPU_HPP
+
+namespace teachos::cpu
+{
+ //! @qualifier platform-defined
+ //! Halt the CPU.
+ //!
+ //! This function terminates execution of the kernel.
+ [[noreturn]] auto halt() -> void;
+} // namespace teachos::cpu
+
+#endif
diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp
new file mode 100644
index 0000000..b51a8a5
--- /dev/null
+++ b/kapi/include/kapi/memory.hpp
@@ -0,0 +1,70 @@
+#ifndef TEACHOS_KAPI_MEMORY_HPP
+#define TEACHOS_KAPI_MEMORY_HPP
+
+#include "kapi/memory/address.hpp" // IWYU pragma: export
+#include "kapi/memory/chunk.hpp" // IWYU pragma: export
+#include "kapi/memory/frame.hpp" // IWYU pragma: export
+#include "kapi/memory/frame_allocator.hpp" // IWYU pragma: export
+#include "kapi/memory/page.hpp" // IWYU pragma: export
+#include "kapi/memory/page_mapper.hpp" // IWYU pragma: export
+
+#include <cstddef>
+#include <optional>
+
+namespace teachos::memory
+{
+
+ //! @qualifier platform-defined
+ //! Initialize the memory subsystem.
+ //!
+ //! @note This function must be implemented by the target platform.
+ //!
+ //! This function initializes the memory subsystem and activates the platform-specific frame allocator and page
+ //! mapper. When this function returns, a valid frame allocator and page mapper are expected to have been registered.
+ auto init() -> void;
+
+ //! @qualifier kernel-defined
+ //! Set the currently active frame allocator.
+ //!
+ //! @param allocator A new frame allocator.
+ //! @return The previously active frame allocator.
+ auto set_frame_allocator(frame_allocator & allocator) -> std::optional<frame_allocator *>;
+
+ //! @qualifier kernel-defined
+ //! Set the currently active page mapper.
+ //!
+ //! @param mapper A new page mapper.
+ //! @return The previously active page mapper.
+ auto set_page_mapper(page_mapper & mapper) -> std::optional<page_mapper *>;
+
+ //! @qualifier kernel-defined
+ //! Allocate a new frame of physical memory
+ //!
+ //! @warning This function will panic if no frame allocator has been registered.
+ //!
+ //! @return An engaged std::optional iff. a frame could be allocated, std::nullopt otherwise.
+ auto allocate_frame() -> std::optional<frame>;
+
+ //! @qualifier kernel-defined
+ //! Map a page onto a frame.
+ //!
+ //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped.
+ //! This function will not ensure that the frame is not already in use.
+ //!
+ //! @param page The page to map.
+ //! @param frame The frame to map the page into.
+ //! @return A pointer to the first byte of the mapped page.
+ auto map(page page, frame frame) -> std::byte *;
+
+ //! @qualifier kernel-defined
+ //! Unmap a page.
+ //!
+ //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped.
+ //! This function will not ensure that the frame is not already in use.
+ //!
+ //! @param page The page to unmap
+ auto unmap(page page) -> void;
+
+} // namespace teachos::memory
+
+#endif
diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp
new file mode 100644
index 0000000..d5496e4
--- /dev/null
+++ b/kapi/include/kapi/memory/address.hpp
@@ -0,0 +1,101 @@
+#ifndef TEACHOS_KAPI_MEMORY_ADDRESS_HPP
+#define TEACHOS_KAPI_MEMORY_ADDRESS_HPP
+
+// IWYU pragma: private, include "kapi/memory.hpp"
+
+#include <bit>
+#include <compare>
+#include <cstddef>
+#include <cstdint>
+
+namespace teachos::memory
+{
+
+ //! @qualifier kernel-defined
+ //! A tag for different address types.
+ enum struct address_type : bool
+ {
+ linear,
+ physical,
+ };
+
+ //! @qualifier kernel-defined
+ //! A physical or virtual address.
+ //!
+ //! This convenience wrapper type is used to ensure that no linear address is passed where a physical one is expected
+ //! and vice versa.
+ //!
+ //! @tparam Type The type of address.
+ template<address_type Type>
+ struct address
+ {
+ //! Construct a null-address.
+ constexpr explicit address() noexcept = default;
+
+ //! Construct an address representing the given value.
+ //!
+ //! @param value The raw value to initialize this address with.
+ constexpr explicit address(std::uintptr_t value) noexcept
+ : m_value{value}
+ {}
+
+ //! Construct an address representing the given pointer value.
+ //!
+ //! @param pointer The pointer value to initialize this address with.
+ explicit address(std::byte * pointer) noexcept
+ : m_value{std::bit_cast<std::uintptr_t>(pointer)}
+ {}
+
+ //! Convert this address into a C++ pointer.
+ explicit operator std::byte *() const noexcept
+ {
+ return std::bit_cast<std::byte *>(m_value);
+ }
+
+ //! Shift this address n bits to the right.
+ //!
+ //! @param n The width of the shift.
+ //! @return A new address representing the result of the shift operation.
+ constexpr auto operator>>(std::size_t n) const noexcept -> address
+ {
+ return address{m_value >> n};
+ }
+
+ //! Apply the given mask to this address.
+ //!
+ //! @param mask The mask to apply
+ //! @return A new address representing the result of the masking operation.
+ template<typename MaskType>
+ constexpr auto operator&(MaskType mask) const noexcept -> MaskType
+ {
+ return static_cast<MaskType>(m_value & mask);
+ }
+
+ //! Check if this address is equal to another one.
+ constexpr auto operator==(address const &) const noexcept -> bool = default;
+
+ //! Lexicographically compare this address with another one.
+ constexpr auto operator<=>(address const &) const noexcept -> std::strong_ordering = default;
+
+ //! Extract the raw value from this address.
+ //!
+ //! @return The raw value of this address.
+ [[nodiscard]] constexpr auto raw() const noexcept -> std::uintptr_t
+ {
+ return m_value;
+ }
+
+ private:
+ //! The raw address value.
+ std::uintptr_t m_value{};
+ };
+
+ //! A linear/virtual address.
+ using linear_address = address<address_type::linear>;
+
+ //! A physical address.
+ using physical_address = address<address_type::physical>;
+
+} // namespace teachos::memory
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/memory/chunk.hpp b/kapi/include/kapi/memory/chunk.hpp
new file mode 100644
index 0000000..fde2e36
--- /dev/null
+++ b/kapi/include/kapi/memory/chunk.hpp
@@ -0,0 +1,104 @@
+#ifndef TEACHOS_KAPI_MEMORY_CHUNK_HPP
+#define TEACHOS_KAPI_MEMORY_CHUNK_HPP
+
+// IWYU pragma: private, include "kapi/memory.hpp"
+
+#include <compare>
+#include <cstddef>
+
+namespace teachos::memory
+{
+
+ //! @qualifier kernel-defined
+ //! A fixed-size unit of memory, indexed by a number.
+ //!
+ //! @tparam AddressType The type of addresses used to index this chunk
+ //! @tparam Size The size of this chunk.
+ template<typename AddressType, std::size_t Size>
+ struct chunk
+ {
+ //! The type of addresses used to index this chunk
+ using address_type = AddressType;
+
+ //! The size of this chunk
+ constexpr auto static size = Size;
+
+ //! Construct a handle referencing the first chunk of the respective address space.
+ constexpr chunk() noexcept = default;
+
+ //! Construct a handle referencing the chunk of memory with the given number.
+ explicit constexpr chunk(std::size_t number) noexcept
+ : m_number{number}
+ {}
+
+ //! Construct a new chunk handle for the chunk containing the given address.
+ //!
+ //! @param address An address contained by the desired chunk.
+ //! @return A handle to a chunk containing the given address.
+ constexpr auto static containing(address_type address) noexcept -> chunk
+ {
+ return chunk{address.raw() / size};
+ }
+
+ //! Get the start address of the chunk referenced by this handle.
+ //!
+ //! @return The address of the first byte contained by the chunk referenced by this handle.
+ [[nodiscard]] constexpr auto start_address() const noexcept -> address_type
+ {
+ return address_type{m_number * size};
+ }
+
+ //! Get the number of the chunk referenced by this handle.
+ //!
+ //! @return The zero-based number of the chunk referenced by this handle.
+ [[nodiscard]] constexpr auto number() const noexcept -> std::size_t
+ {
+ return m_number;
+ }
+
+ //! Get a handle n chunks after the one referenced by this handle.
+ //!
+ //! @param n The positive offset to this chunk.
+ //! @return A handle referencing the chunk n chunks after the one referenced by this handle.
+ constexpr auto operator+(std::size_t n) const noexcept -> chunk
+ {
+ return chunk{m_number + n};
+ }
+
+ //! Let this handle reference the next chunk after the currently reference one.
+ //!
+ //! @return A handle referencing the same chunk as this handle did before the operation.
+ constexpr auto operator++(int) noexcept -> chunk
+ {
+ auto copy = *this;
+ ++*this;
+ return copy;
+ }
+
+ //! Let this handle reference the next chunk after the currently reference one.
+ //!
+ //! @return A reference to this handle.
+ constexpr auto operator++() noexcept -> chunk &
+ {
+ ++m_number;
+ return *this;
+ }
+
+ //! Check if this chunk handle reference the same chunk as another one.
+ //!
+ //! @param other Another chunk handle.
+ constexpr auto operator==(chunk const & other) const noexcept -> bool = default;
+
+ //! Compare the number of the chunk referenced by this handle to the one reference by another one.
+ //!
+ //! @param other Another chunk handle.
+ constexpr auto operator<=>(chunk const & other) const noexcept -> std::strong_ordering = default;
+
+ private:
+ //! The number of the currently referenced chunk.
+ std::size_t m_number{};
+ };
+
+} // namespace teachos::memory
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp
new file mode 100644
index 0000000..49f3bb0
--- /dev/null
+++ b/kapi/include/kapi/memory/frame.hpp
@@ -0,0 +1,39 @@
+#ifndef TEACHOS_KAPI_MEMORY_FRAME_HPP
+#define TEACHOS_KAPI_MEMORY_FRAME_HPP
+
+// IWYU pragma: private, include "kapi/memory.hpp"
+
+#include "kapi/memory/address.hpp"
+#include "kapi/memory/chunk.hpp"
+
+namespace teachos::memory
+{
+
+ //! @qualifier kernel-defined
+ //! A handle to a frame of physical memory.
+ //!
+ //! @note Contrary to the address types, this type is modeled using inheritance to support future extensions.
+ struct frame : chunk<physical_address, PLATFORM_FRAME_SIZE>
+ {
+ using chunk::chunk;
+
+ //! @copydoc chunk::containing
+ //!
+ //! @note This factory shadows the base factory to aid in type deduction.
+ constexpr auto static containing(physical_address address) noexcept -> frame
+ {
+ return frame{chunk::containing(address)};
+ }
+
+ //! Convert a base chunk into a page.
+ //!
+ //! This constructor allows for conversion from chunk<physical_address, PLATFORM_FRAME_SIZE> to a frame for
+ //! convenience. It is deliberately not explicit.
+ constexpr frame(chunk other)
+ : chunk{other}
+ {}
+ };
+
+} // namespace teachos::memory
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/memory/frame_allocator.hpp b/kapi/include/kapi/memory/frame_allocator.hpp
new file mode 100644
index 0000000..fb6bc0d
--- /dev/null
+++ b/kapi/include/kapi/memory/frame_allocator.hpp
@@ -0,0 +1,43 @@
+#ifndef TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP
+#define TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP
+
+// IWYU pragma: private, include "kapi/memory.hpp"
+
+#include "kapi/memory/frame.hpp"
+
+#include <optional>
+
+namespace teachos::memory
+{
+
+ //! The interface of all frame allocators.
+ //!
+ //! A frame allocator is responsible for the allocation, and deallocation, of frames of physical memory. Frames
+ //! obtained from an allocator shall only be deallocated, or released, via the same allocator. When a frame allocated
+ //! from one allocator is release via a different one (instance or type), the behavior is undefined.
+ struct frame_allocator
+ {
+ frame_allocator(frame_allocator const &) = delete;
+ frame_allocator(frame_allocator &&) = delete;
+ auto operator=(frame_allocator const &) -> frame_allocator & = delete;
+ auto operator=(frame_allocator &&) -> frame_allocator & = delete;
+
+ virtual ~frame_allocator() = default;
+
+ //! Allocate a frame of physical memory.
+ //!
+ //! @return An engaged std::optional iff. a new frame could be allocated, std::nullopt otherwise.
+ virtual auto allocate() noexcept -> std::optional<frame> = 0;
+
+ //! Release a frame of physical memory.
+ //!
+ //! @param frame A frame of physical memory, previously acquired by a call to the #allocate function.
+ virtual auto release(frame frame) -> void = 0;
+
+ protected:
+ frame_allocator() = default;
+ };
+
+} // namespace teachos::memory
+
+#endif // TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP \ No newline at end of file
diff --git a/kapi/include/kapi/memory/page.hpp b/kapi/include/kapi/memory/page.hpp
new file mode 100644
index 0000000..57f4f09
--- /dev/null
+++ b/kapi/include/kapi/memory/page.hpp
@@ -0,0 +1,39 @@
+#ifndef TEACHOS_KAPI_MEMORY_PAGE_HPP
+#define TEACHOS_KAPI_MEMORY_PAGE_HPP
+
+// IWYU pragma: private, include "kapi/memory.hpp"
+
+#include "kapi/memory/address.hpp"
+#include "kapi/memory/chunk.hpp"
+
+namespace teachos::memory
+{
+
+ //! @qualifier kernel-defined
+ //! A handle to a page of virtual memory.
+ //!
+ //! @note Contrary to the address types, this type is modeled using inheritance to support future extensions.
+ struct page : chunk<linear_address, PLATFORM_PAGE_SIZE>
+ {
+ using chunk::chunk;
+
+ //! @copydoc chunk::containing
+ //!
+ //! @note This factory shadows the base factory to aid in type deduction.
+ constexpr auto static containing(linear_address address) noexcept -> page
+ {
+ return page{chunk::containing(address)};
+ }
+
+ //! Convert a base chunk into a page.
+ //!
+ //! This constructor allows for conversion from chunk<linear_address, PLATFORM_PAGE_SIZE> to a page for convenience.
+ //! It is deliberately not explicit.
+ constexpr page(chunk other)
+ : chunk{other}
+ {}
+ };
+
+} // namespace teachos::memory
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/memory/page_mapper.hpp b/kapi/include/kapi/memory/page_mapper.hpp
new file mode 100644
index 0000000..2396249
--- /dev/null
+++ b/kapi/include/kapi/memory/page_mapper.hpp
@@ -0,0 +1,87 @@
+#ifndef TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP
+#define TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP
+
+// IWYU pragma: private, include "kapi/memory.hpp"
+
+#include "kapi/memory/frame.hpp"
+#include "kapi/memory/page.hpp"
+
+#include <kstd/ext/bitfield_enum>
+
+#include <type_traits>
+
+namespace teachos::memory
+{
+
+ //! @qualifier platform-implemented
+ //! The interface of a type allowing the mapping, and unmapping, of pages onto frames.
+ struct page_mapper
+ {
+ page_mapper(page_mapper const &) = delete;
+ page_mapper(page_mapper &&) = delete;
+ auto operator=(page_mapper const &) -> page_mapper & = delete;
+ auto operator=(page_mapper &&) -> page_mapper & = delete;
+
+ //! Platform independent page mapping flags
+ enum struct flags : std::uint64_t
+ {
+ empty,
+ writable = 1 << 0, //! The page is writable.
+ executable = 1 << 1, //! The page contains executable instructions.
+ uncached = 1 << 2, //! The page contents must not be cached.
+ supervisor_only = 1 << 3, //! The page is only accessible in supervisor mode.
+ };
+
+ virtual ~page_mapper() = default;
+
+ //! Map a page into a given frame, applying the given flags.
+ //!
+ //! @param page The page to map.
+ //! @param frame The frame to map the page into.
+ //! @param flags The flags to map the page with.
+ //! @return A pointer to the first byte of mapped page.
+ virtual auto map(page page, frame frame, flags flags) -> std::byte * = 0;
+
+ //! Unmap the given page.
+ //!
+ //! @warning If the provided page is not mapped, the behavior is undefined. Implementation are encourage to
+ //! terminate execution via a kernel panic.
+ //!
+ //! @param page The page to unmap.
+ virtual auto unmap(page page) -> void = 0;
+
+ //! Try to unmap the given page.
+ //!
+ //! @param page The page to unmap
+ //! @return true iff. the page was successfully unmapped, false otherwise.
+ virtual auto try_unmap(page page) noexcept -> bool = 0;
+
+ //! @qualifier kernel-defined
+ //! Map a page into a given frame, applyint the given flags.
+ //!
+ //! @tparam T The type of data contained in the page.
+ //! @param page The page to map.
+ //! @param frame The frame to map the page into.
+ //! @param flags The flags to map the page with.
+ //! @return A pointer to the first T in the page.
+ template<typename T>
+ [[nodiscard]] auto map_as(page page, frame frame, flags flags) -> T *
+ {
+ return std::bit_cast<T *>(map(page, frame, flags));
+ }
+
+ protected:
+ page_mapper() = default;
+ };
+
+} // namespace teachos::memory
+
+namespace kstd::ext
+{
+ template<>
+ struct is_bitfield_enum<teachos::memory::page_mapper::flags> : std::true_type
+ {
+ };
+} // namespace kstd::ext
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/system.hpp b/kapi/include/kapi/system.hpp
new file mode 100644
index 0000000..e6b9826
--- /dev/null
+++ b/kapi/include/kapi/system.hpp
@@ -0,0 +1,20 @@
+#ifndef TEACHOS_KAPI_SYSTEM_HPP
+#define TEACHOS_KAPI_SYSTEM_HPP
+
+#include <source_location>
+#include <string_view>
+
+namespace teachos::system
+{
+
+ //! @qualifier kernel-defined
+ //! Terminate kernel execution with the given error message.
+ //!
+ //! This function terminates the execution of the kernel and attempts to issue the given error message to the user.
+ //!
+ //! @param message The message associated with the panic
+ [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void;
+
+} // namespace teachos::system
+
+#endif
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
new file mode 100644
index 0000000..6bddf7c
--- /dev/null
+++ b/kernel/CMakeLists.txt
@@ -0,0 +1,36 @@
+add_executable("kernel"
+ "src/kstd.cpp"
+ "src/main.cpp"
+
+ # Platform Independent KAPI implementation
+ "src/kapi/cio.cpp"
+ "src/kapi/memory.cpp"
+ "src/kapi/system.cpp"
+)
+
+target_include_directories("kernel" PRIVATE
+ "include"
+)
+
+target_link_libraries("kernel" PRIVATE
+ "os::arch"
+ "os::kapi"
+)
+
+target_link_options("kernel" PRIVATE
+ "-T${KERNEL_LINKER_SCRIPT}"
+ "-no-pie"
+ "-nostdlib"
+)
+
+set_property(TARGET "kernel"
+ APPEND
+ PROPERTY LINK_DEPENDS
+ "${KERNEL_LINKER_SCRIPT}"
+)
+
+target_disassemble("kernel")
+target_extract_debug_symbols("kernel")
+target_strip("kernel")
+
+target_generate_bootable_iso("kernel")
diff --git a/kernel/src/kapi/cio.cpp b/kernel/src/kapi/cio.cpp
new file mode 100644
index 0000000..66493b6
--- /dev/null
+++ b/kernel/src/kapi/cio.cpp
@@ -0,0 +1,57 @@
+#include "kapi/cio.hpp"
+
+#include <optional>
+#include <string_view>
+#include <utility>
+
+namespace teachos::cio
+{
+ namespace
+ {
+ struct null_device final : public output_device
+ {
+ null_device static instance;
+
+ auto write(std::string_view) -> void override {}
+ auto writeln(std::string_view) -> void override {}
+
+ auto write_error(std::string_view) -> void override {}
+ auto writeln_error(std::string_view) -> void override {}
+ };
+
+ constinit null_device null_device::instance;
+ } // namespace
+
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ constinit auto active_device = static_cast<output_device *>(&null_device::instance);
+
+ auto set_output_device(output_device & device) -> std::optional<output_device *>
+ {
+ if (&device == active_device)
+ {
+ return {};
+ }
+ return std::exchange(active_device, &device);
+ }
+
+ auto print(std::string_view text) -> void
+ {
+ active_device->write(text);
+ }
+
+ auto println(std::string_view text) -> void
+ {
+ active_device->writeln(text);
+ }
+
+ auto print_error(std::string_view text) -> void
+ {
+ active_device->write_error(text);
+ }
+
+ auto println_error(std::string_view text) -> void
+ {
+ active_device->writeln_error(text);
+ }
+
+} // namespace teachos::cio \ No newline at end of file
diff --git a/kernel/src/kapi/memory.cpp b/kernel/src/kapi/memory.cpp
new file mode 100644
index 0000000..d6c84e1
--- /dev/null
+++ b/kernel/src/kapi/memory.cpp
@@ -0,0 +1,91 @@
+#include "kapi/memory.hpp"
+
+#include "kapi/system.hpp"
+
+#include <cstddef>
+#include <optional>
+#include <utility>
+
+namespace teachos::memory
+{
+
+ namespace
+ {
+ struct bad_frame_allocator final : public frame_allocator
+ {
+ bad_frame_allocator static instance;
+
+ auto allocate() noexcept -> std::optional<frame> override
+ {
+ system::panic("Tried to allocate a frame without an active allocator.");
+ }
+
+ auto release(frame) -> void override
+ {
+ system::panic("Tried to release a frame without an active allocator.");
+ }
+ };
+
+ struct bad_page_mapper final : public page_mapper
+ {
+ bad_page_mapper static instance;
+
+ auto map(page, frame, flags) -> std::byte * override
+ {
+ system::panic("Tried to map a page without an active mapper.");
+ }
+
+ auto unmap(page) -> void override
+ {
+ system::panic("Tried to unmap a page without an active mapper.");
+ }
+
+ auto try_unmap(page) noexcept -> bool override
+ {
+ return false;
+ }
+ };
+
+ constinit bad_frame_allocator bad_frame_allocator::instance{};
+ constinit bad_page_mapper bad_page_mapper::instance{};
+ } // namespace
+
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ constinit auto active_frame_allocator = static_cast<frame_allocator *>(&bad_frame_allocator::instance);
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ constinit auto active_page_mapper = static_cast<page_mapper *>(&bad_page_mapper::instance);
+
+ auto set_frame_allocator(frame_allocator & allocator) -> std::optional<frame_allocator *>
+ {
+ if (&allocator == active_frame_allocator)
+ {
+ return {};
+ }
+ return std::exchange(active_frame_allocator, &allocator);
+ }
+
+ auto set_page_mapper(page_mapper & mapper) -> std::optional<page_mapper *>
+ {
+ if (&mapper == active_page_mapper)
+ {
+ return {};
+ }
+ return std::exchange(active_page_mapper, &mapper);
+ }
+
+ auto allocate_frame() -> std::optional<frame>
+ {
+ return active_frame_allocator->allocate();
+ }
+
+ auto map(page page, frame frame) -> std::byte *
+ {
+ return active_page_mapper->map(page, frame, page_mapper::flags::empty);
+ }
+
+ auto unmap(page page) -> void
+ {
+ return active_page_mapper->unmap(page);
+ }
+
+} // namespace teachos::memory \ No newline at end of file
diff --git a/kernel/src/kapi/system.cpp b/kernel/src/kapi/system.cpp
new file mode 100644
index 0000000..228c03f
--- /dev/null
+++ b/kernel/src/kapi/system.cpp
@@ -0,0 +1,23 @@
+#include "kapi/system.hpp"
+
+#include "kapi/cio.hpp"
+#include "kapi/cpu.hpp"
+
+#include <source_location>
+#include <string_view>
+
+namespace teachos::system
+{
+
+ [[gnu::weak]]
+ auto panic(std::string_view message, std::source_location location) -> void
+ {
+ cio::println_error("!!!Kernel Panic!!! ");
+ cio::println_error(message);
+ cio::println_error(location.file_name());
+ cio::println_error(location.function_name());
+
+ cpu::halt();
+ }
+
+} // namespace teachos::system
diff --git a/kernel/src/kstd.cpp b/kernel/src/kstd.cpp
new file mode 100644
index 0000000..41c4d60
--- /dev/null
+++ b/kernel/src/kstd.cpp
@@ -0,0 +1,16 @@
+#include "kapi/system.hpp"
+
+#include <kstd/bits/os.hpp>
+
+#include <source_location>
+#include <string_view>
+
+namespace kstd::os
+{
+
+ auto panic(std::string_view message, std::source_location location) -> void
+ {
+ teachos::system::panic(message, location);
+ }
+
+} // namespace kstd::os \ No newline at end of file
diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp
new file mode 100644
index 0000000..3394275
--- /dev/null
+++ b/kernel/src/main.cpp
@@ -0,0 +1,14 @@
+#include "kapi/cio.hpp"
+#include "kapi/memory.hpp"
+#include "kapi/system.hpp"
+
+auto main() -> int
+{
+ teachos::cio::init();
+ teachos::cio::println("[OS] IO subsystem initialized.");
+
+ teachos::memory::init();
+ teachos::cio::println("[OS] Memory subsystem initialized.");
+
+ teachos::system::panic("Returning from kernel main!");
+}
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
new file mode 100644
index 0000000..58d9796
--- /dev/null
+++ b/libs/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory("elf" EXCLUDE_FROM_ALL SYSTEM)
+add_subdirectory("kstd" EXCLUDE_FROM_ALL SYSTEM)
+add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) \ No newline at end of file
diff --git a/libs/elf/CMakeLists.txt b/libs/elf/CMakeLists.txt
new file mode 100644
index 0000000..66e59ee
--- /dev/null
+++ b/libs/elf/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_library("elf" INTERFACE)
+add_library("libs::elf" ALIAS "elf")
+
+target_sources("elf" INTERFACE
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ "include/elf/format.hpp"
+ "include/elf/section_header.hpp"
+
+)
+
+target_include_directories("elf" INTERFACE
+ "include"
+)
+
+set_target_properties("elf" PROPERTIES
+ VERIFY_INTERFACE_HEADER_SETS YES
+) \ No newline at end of file
diff --git a/libs/elf/include/elf/format.hpp b/libs/elf/include/elf/format.hpp
new file mode 100644
index 0000000..b3220f5
--- /dev/null
+++ b/libs/elf/include/elf/format.hpp
@@ -0,0 +1,15 @@
+#ifndef ELF_FORMAT_HPP
+#define ELF_FORMAT_HPP
+
+namespace elf
+{
+
+ enum struct format
+ {
+ elf32,
+ elf64,
+ };
+
+} // namespace elf
+
+#endif \ No newline at end of file
diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp
new file mode 100644
index 0000000..3afe334
--- /dev/null
+++ b/libs/elf/include/elf/section_header.hpp
@@ -0,0 +1,99 @@
+#ifndef ELF_SECTION_HEADER_HPP
+#define ELF_SECTION_HEADER_HPP
+
+#include "format.hpp"
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace elf
+{
+
+ template<format Format>
+ constexpr auto inline section_header_size = std::numeric_limits<std::size_t>::max();
+
+ template<>
+ constexpr auto inline section_header_size<format::elf32> = 40uz;
+
+ template<>
+ constexpr auto inline section_header_size<format::elf64> = 64uz;
+
+ template<format Format>
+ struct section_header
+ {
+ using format_uint = std::conditional_t<Format == format::elf32, std::uint32_t, std::uint64_t>;
+
+ enum struct header_type : std::uint32_t
+ {
+ null = 0, ///< Is inactive
+ program_data = 1, ///< Contains program data
+ symbol_table = 2, ///< Contains a symbol table
+ string_table = 3, ///< Contains a string table
+ relocation_entries_with_addends = 4, ///< Contains relocation information with addends
+ hash_table = 5, ///< Contains a symbol hash table
+ dynamic_linking_entries = 6, ///< Contains dynamic linking information
+ notes = 7, ///< Contains additional notes about the object file
+ no_content = 8, ///< Contains no data
+ relocation_entries_without_addends = 9, ///< Contains relocation information without addends
+ reserved = 10, ///< Reserved for future use
+ dynamic_linker_symbol_table = 11, ///< Contains the dynamic linker symbol table
+ init_array = 14, ///< Contains an array of constructor pointers
+ fini_array = 15, ///< Contains an array of destructor pointers
+ preinit_array = 16, ///< Contains an array of pre-constructor pointers
+ group_table = 17, ///< Defines a section group
+ extended_section_header_indices = 18, ///< Contains extended section header indices
+ };
+
+ enum struct header_flags : format_uint
+ {
+ writeable = 0x1, ///< Contains writable data
+ allocated = 0x2, ///< Occupies memory during execution
+ executable = 0x4, ///< Contains executable instructions
+ mergeable = 0x10, ///< Contained data may be merged for deduplication
+ strings = 0x20, ///< Contains null-terminated strings
+ info_link = 0x40, ///< Contains the section header index of linked section
+ link_order = 0x80, ///< Must respect linking location relative to linked section
+ os_specific = 0x100, ///< Must be handled in an OS specific way
+ group_member = 0x200, ///< Is a member of a section group
+ thread_local_storage = 0x400, ///< Contains thread local storage data
+ compressed = 0x800, ///< Is compressed
+ };
+
+ //! Check if the section is allocated
+ [[nodiscard]] constexpr auto allocated() const noexcept -> bool
+ {
+ return std::to_underlying(flags) & std::to_underlying(header_flags::allocated);
+ }
+
+ //! Check if the section is executable
+ [[nodiscard]] constexpr auto executable() const noexcept -> bool
+ {
+ return std::to_underlying(flags) & std::to_underlying(header_flags::executable);
+ }
+
+ //! Check if the section is writeable
+ [[nodiscard]] constexpr auto writable() const noexcept -> bool
+ {
+ return std::to_underlying(flags) & std::to_underlying(header_flags::writeable);
+ }
+
+ std::uint32_t name_offset; ///< Offset into the section header string table, defining the section name
+ header_type type; ///< Type of this section
+ header_flags flags; ///< Flags of this section
+ format_uint virtual_load_address; ///< Virtual address where this section is loaded
+ format_uint file_offset; ///< Offset of the start of this section's data in the file
+ format_uint size; ///< Size of this section in memory
+ std::uint32_t linked_section; ///< Index of a section this section is linked to
+ std::uint32_t extra_info; ///< Additional information for this section (type and flag dependent)
+ format_uint alignment; ///< Alignment requirement of this section in memory
+ format_uint entry_size; ///< Size of the entries inside this section (if any)
+ };
+
+ static_assert(sizeof(section_header<format::elf32>) == section_header_size<format::elf32>);
+ static_assert(sizeof(section_header<format::elf64>) == section_header_size<format::elf64>);
+
+} // namespace elf
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt
new file mode 100644
index 0000000..d83e704
--- /dev/null
+++ b/libs/kstd/CMakeLists.txt
@@ -0,0 +1,40 @@
+add_library("kstd" STATIC)
+add_library("libs::kstd" ALIAS "kstd")
+
+set(KSTD_LIBC_SYMBOLS
+ "abort"
+ "strlen"
+ "memcmp"
+)
+
+target_sources("kstd" PRIVATE
+ "src/bits/os.cpp"
+ "src/libc/stdlib.cpp"
+ "src/libc/string.cpp"
+ "src/mutex.cpp"
+)
+
+target_sources("kstd" PUBLIC
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ "include/kstd/bits/os.hpp"
+ "include/kstd/bits/shared_ptr.hpp"
+ "include/kstd/bits/unique_ptr.hpp"
+
+ "include/kstd/ext/bitfield_enum"
+
+ "include/kstd/asm_ptr"
+ "include/kstd/memory"
+ "include/kstd/mutex"
+ "include/kstd/stack"
+ "include/kstd/vector"
+)
+
+target_include_directories("kstd" PUBLIC
+ "include"
+)
+
+list(TRANSFORM KSTD_LIBC_SYMBOLS PREPEND "-Wl,--undefined=")
+
+target_link_options("kstd" INTERFACE ${KSTD_LIBC_SYMBOLS}) \ No newline at end of file
diff --git a/libs/kstd/include/kstd/asm_ptr b/libs/kstd/include/kstd/asm_ptr
new file mode 100644
index 0000000..e8636c3
--- /dev/null
+++ b/libs/kstd/include/kstd/asm_ptr
@@ -0,0 +1,77 @@
+#ifndef KSTD_ASM_POINTER_HPP
+#define KSTD_ASM_POINTER_HPP
+
+#include <bit>
+
+namespace kstd
+{
+
+ /**
+ * @brief A pointer that is defined in some assembly source file.
+ *
+ * @tparam Type The type of the pointer
+ */
+ template<typename Type>
+ struct asm_ptr
+ {
+ using value_type = Type;
+ using pointer = value_type *;
+ using const_pointer = value_type const *;
+ using reference = value_type &;
+ using const_reference = value_type const &;
+
+ asm_ptr() = delete;
+ asm_ptr(asm_ptr const &) = delete;
+ asm_ptr(asm_ptr &&) = delete;
+ ~asm_ptr() = delete;
+
+ constexpr auto operator=(asm_ptr const &) = delete;
+ constexpr auto operator=(asm_ptr &&) = delete;
+
+ auto get() const noexcept -> pointer
+ {
+ return m_ptr;
+ }
+
+ constexpr auto operator+(std::ptrdiff_t offset) const noexcept -> pointer
+ {
+ return std::bit_cast<pointer>(m_ptr) + offset;
+ }
+
+ constexpr auto operator*() noexcept -> reference
+ {
+ return *(std::bit_cast<pointer>(m_ptr));
+ }
+
+ constexpr auto operator*() const noexcept -> const_reference
+ {
+ return *(std::bit_cast<const_pointer>(m_ptr));
+ }
+
+ constexpr auto operator[](std::ptrdiff_t offset) noexcept -> reference
+ {
+ return *(*this + offset);
+ }
+
+ constexpr auto operator[](std::ptrdiff_t offset) const noexcept -> const_reference
+ {
+ return *(*this + offset);
+ }
+
+ constexpr auto operator->() noexcept -> pointer
+ {
+ return m_ptr;
+ }
+
+ constexpr auto operator->() const noexcept -> const_pointer
+ {
+ return m_ptr;
+ }
+
+ private:
+ pointer m_ptr;
+ };
+
+} // namespace kstd
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp
new file mode 100644
index 0000000..0474f16
--- /dev/null
+++ b/libs/kstd/include/kstd/bits/os.hpp
@@ -0,0 +1,34 @@
+#ifndef KSTD_OS_HPP
+#define KSTD_OS_HPP
+
+#include <source_location>
+#include <string_view>
+
+namespace kstd::os
+{
+ /**
+ * @brief Handle an unrecoverable library error.
+ *
+ * The operating system kernel may choose to implement this function in order to try to perform additional cleanup
+ * before terminating execution. If the kernel does not implement this function, the default implementation will be
+ * chosen. This default implementation doest nothing.
+ */
+ [[noreturn]]
+ auto abort() -> void;
+
+ /**
+ * @brief Terminate execution of the operating system.
+ *
+ * The operating system must implement this function. This function must terminate the execution of the operating
+ * system kernel as is. It may choose to restart the kernel or to halt execution entirely. The implementation must
+ * guarantee that execution never return from this function.
+ *
+ * @param message A message describing the reason for termination of execution.
+ * @param where The source code location at which the panic was triggered. In general, no argument shall be provided
+ * for this parameter, thus implicitly capturing the location at which the call originates.
+ */
+ [[noreturn]]
+ auto panic(std::string_view message, std::source_location where = std::source_location::current()) -> void;
+} // namespace kstd::os
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/stl/shared_pointer.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp
index c9796a8..4bcf499 100644
--- a/arch/x86_64/include/arch/stl/shared_pointer.hpp
+++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp
@@ -1,16 +1,16 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP
-#define TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP
+#ifndef KSTD_BITS_SHARED_PTR_HPP
+#define KSTD_BITS_SHARED_PTR_HPP
#include <atomic>
-namespace teachos::arch::stl
+namespace kstd
{
/**
* @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several
- * shared_pointer objects may own the same object. The object is destroyed and its memory deallocated when either of
- * the following happens: the last remaining shared_pointer owning the object is destroyed; the last remaining
- * shared_pointer owning the object is assigned another pointer via operator= or reset(). A
- * shared_pointer can share ownership of an object while storing a pointer to another object. This feature can be used
+ * shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of
+ * the following happens: the last remaining shared_ptr owning the object is destroyed; the last remaining
+ * shared_ptr owning the object is assigned another pointer via operator= or reset(). A
+ * shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used
* to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(),
* the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count
* reaches zero.
@@ -18,7 +18,7 @@ namespace teachos::arch::stl
* @tparam T The type of the managed object.
*/
template<typename T>
- struct shared_pointer
+ struct shared_ptr
{
/**
* @brief Constructor.
@@ -26,7 +26,7 @@ namespace teachos::arch::stl
* @param pointer A pointer to an object to manage (default is nullptr).
*/
[[gnu::section(".stl_text")]]
- explicit shared_pointer(T * pointer = nullptr)
+ explicit shared_ptr(T * pointer = nullptr)
: pointer(pointer)
, ref_count(new std::atomic<std::size_t>(pointer != nullptr ? 1 : 0))
{
@@ -36,10 +36,10 @@ namespace teachos::arch::stl
/**
* @brief Copy constructor.
*
- * @param other The shared_pointer to copy from.
+ * @param other The shared_ptr to copy from.
*/
[[gnu::section(".stl_text")]]
- shared_pointer(const shared_pointer & other)
+ shared_ptr(shared_ptr const & other)
: pointer(other.pointer)
, ref_count(other.ref_count)
{
@@ -52,10 +52,10 @@ namespace teachos::arch::stl
/**
* @brief Move constructor.
*
- * @param other The shared_pointer to move from.
+ * @param other The shared_ptr to move from.
*/
[[gnu::section(".stl_text")]]
- shared_pointer(shared_pointer && other) noexcept
+ shared_ptr(shared_ptr && other) noexcept
: pointer(other.pointer)
, ref_count(other.ref_count)
{
@@ -72,7 +72,7 @@ namespace teachos::arch::stl
* @return Reference to this shared pointer.
*/
[[gnu::section(".stl_text")]]
- shared_pointer & operator=(const shared_pointer & other)
+ shared_ptr & operator=(shared_ptr const & other)
{
if (this != &other)
{
@@ -97,7 +97,7 @@ namespace teachos::arch::stl
* @return Reference to this shared pointer.
*/
[[gnu::section(".stl_text")]]
- shared_pointer & operator=(shared_pointer && other) noexcept
+ shared_ptr & operator=(shared_ptr && other) noexcept
{
if (this != &other)
{
@@ -115,7 +115,7 @@ namespace teachos::arch::stl
* @brief Destructor. Cleans up resources if necessary.
*/
[[gnu::section(".stl_text")]]
- ~shared_pointer()
+ ~shared_ptr()
{
cleanup();
}
@@ -137,10 +137,10 @@ namespace teachos::arch::stl
* @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not
* adjusted.
*
- * @param other The shared_pointer to swap with.
+ * @param other The shared_ptr to swap with.
*/
[[gnu::section(".stl_text")]]
- void swap(shared_pointer & other)
+ void swap(shared_ptr & other)
{
std::swap(pointer, other.pointer);
std::swap(ref_count, other.ref_count);
@@ -180,7 +180,7 @@ namespace teachos::arch::stl
}
/**
- * @brief Returns the number of different shared_pointer instances (*this included) managing the current object. If
+ * @brief Returns the number of different shared_ptr instances (*this included) managing the current object. If
* there is no managed object, ​0​ is returned.
*
* @note Common use cases include comparison with ​0​. If use_count returns zero, the shared pointer is empty
@@ -216,11 +216,11 @@ namespace teachos::arch::stl
* @brief Defaulted three-way comparator operator.
*/
[[gnu::section(".stl_text")]]
- auto operator<=>(const shared_pointer & other) const = default;
+ auto operator<=>(shared_ptr const & other) const = default;
private:
/**
- * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object.
+ * @brief Releases ownership and deletes the object if this was the last reference to the owned managed object.
*/
[[gnu::section(".stl_text")]]
auto cleanup() -> void
@@ -244,15 +244,15 @@ namespace teachos::arch::stl
* @param lhs, rhs Smart pointers whose contents to swap.
*/
template<typename T>
- auto swap(shared_pointer<T> & lhs, shared_pointer<T> & rhs) -> void
+ auto swap(shared_ptr<T> & lhs, shared_ptr<T> & rhs) -> void
{
lhs.swap(rhs);
}
/**
- * @brief Constructs an object of type T and wraps it in a shared_pointer. Constructs a non-array type T. The
+ * @brief Constructs an object of type T and wraps it in a shared_ptr. Constructs a non-array type T. The
* arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is
- * not an array type. The function is equivalent to: shared_pointer<T>(new T(std::forward<Args>(args)...)).
+ * not an array type. The function is equivalent to: shared_ptr<T>(new T(std::forward<Args>(args)...)).
*
* @tparam T Type of the managed object.
* @tparam Args Argument types for T's constructor.
@@ -260,10 +260,10 @@ namespace teachos::arch::stl
* @returns Shared_pointer of an instance of type T.
*/
template<typename T, typename... Args>
- auto make_shared(Args &&... args) -> shared_pointer<T>
+ auto make_shared(Args &&... args) -> shared_ptr<T>
{
- return shared_pointer<T>(new T(std::forward<Args>(args)...));
+ return shared_ptr<T>(new T(std::forward<Args>(args)...));
}
-} // namespace teachos::arch::stl
+} // namespace kstd
-#endif // TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP \ No newline at end of file
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/stl/unique_pointer.hpp b/libs/kstd/include/kstd/bits/unique_ptr.hpp
index 03b4ef3..5f54848 100644
--- a/arch/x86_64/include/arch/stl/unique_pointer.hpp
+++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp
@@ -1,16 +1,18 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_UNIQUE_POINTER_HPP
-#define TEACHOS_ARCH_X86_64_STL_UNIQUE_POINTER_HPP
+#ifndef KSTD_BITS_UNIQUE_POINTER_HPP
+#define KSTD_BITS_UNIQUE_POINTER_HPP
-namespace teachos::arch::stl
+#include <utility>
+
+namespace kstd
{
/**
* @brief Unique_pointer is a smart pointer that owns (is responsible for) and manages another object via a pointer
- * and subsequently disposes of that object when the unique_pointer goes out of scope.
+ * and subsequently disposes of that object when the unique_ptr goes out of scope.
*
* @tparam T Type of the managed object.
*/
template<typename T>
- struct unique_pointer
+ struct unique_ptr
{
/**
* @brief Constructor.
@@ -18,7 +20,7 @@ namespace teachos::arch::stl
* @param ptr A pointer to an object to manage (default is nullptr).
*/
[[gnu::section(".stl_text")]]
- explicit unique_pointer(T * ptr = nullptr)
+ explicit unique_ptr(T * ptr = nullptr)
: pointer(ptr)
{
// Nothing to do.
@@ -28,7 +30,7 @@ namespace teachos::arch::stl
* @brief Destructor that deletes the managed object.
*/
[[gnu::section(".stl_text")]]
- ~unique_pointer()
+ ~unique_ptr()
{
delete pointer;
}
@@ -36,12 +38,12 @@ namespace teachos::arch::stl
/**
* @brief Deleted copy constructor to enforce unique ownership.
*/
- unique_pointer(const unique_pointer &) = delete;
+ unique_ptr(unique_ptr const &) = delete;
/**
* @brief Deleted copy assignment operator to enforce unique ownership.
*/
- auto operator=(const unique_pointer &) -> unique_pointer & = delete;
+ auto operator=(unique_ptr const &) -> unique_ptr & = delete;
/**
* @brief Move constructor.
@@ -49,7 +51,7 @@ namespace teachos::arch::stl
* @param other Unique pointer to move from.
*/
[[gnu::section(".stl_text")]]
- unique_pointer(unique_pointer && other) noexcept
+ unique_ptr(unique_ptr && other) noexcept
: pointer(other.pointer)
{
other.pointer = nullptr;
@@ -62,7 +64,7 @@ namespace teachos::arch::stl
* @return Reference to this unique pointer.
*/
[[gnu::section(".stl_text")]]
- auto operator=(unique_pointer && other) noexcept -> unique_pointer &
+ auto operator=(unique_ptr && other) noexcept -> unique_ptr &
{
if (this != &other)
{
@@ -155,7 +157,7 @@ namespace teachos::arch::stl
* @param other Another unique_ptr object to swap the managed object and the deleter with.
*/
[[gnu::section(".stl_text")]]
- auto swap(unique_pointer & other) -> void
+ auto swap(unique_ptr & other) -> void
{
using std::swap;
swap(pointer, other.pointer);
@@ -165,7 +167,7 @@ namespace teachos::arch::stl
* @brief Defaulted three-way comparator operator.
*/
[[gnu::section(".stl_text")]]
- auto operator<=>(const unique_pointer & other) const = default;
+ auto operator<=>(unique_ptr const & other) const = default;
private:
T * pointer; ///< The managed pointer.
@@ -179,15 +181,15 @@ namespace teachos::arch::stl
* @param lhs, rhs Smart pointers whose contents to swap.
*/
template<typename T>
- auto swap(unique_pointer<T> & lhs, unique_pointer<T> & rhs) -> void
+ auto swap(unique_ptr<T> & lhs, unique_ptr<T> & rhs) -> void
{
lhs.swap(rhs);
}
/**
- * @brief Constructs an object of type T and wraps it in a unique_pointer. Constructs a non-array type T. The
+ * @brief Constructs an object of type T and wraps it in a unique_ptr. Constructs a non-array type T. The
* arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is
- * not an array type. The function is equivalent to: unique_pointer<T>(new T(std::forward<Args>(args)...)).
+ * not an array type. The function is equivalent to: unique_ptr<T>(new T(std::forward<Args>(args)...)).
*
* @tparam T Type of the managed object.
* @tparam Args Argument types for T's constructor.
@@ -195,10 +197,10 @@ namespace teachos::arch::stl
* @returns Unique_pointer of an instance of type T.
*/
template<typename T, typename... Args>
- auto make_unique(Args &&... args) -> unique_pointer<T>
+ auto make_unique(Args &&... args) -> unique_ptr<T>
{
- return unique_pointer<T>(new T(std::forward<Args>(args)...));
+ return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
-} // namespace teachos::arch::stl
+} // namespace kstd
-#endif // TEACHOS_ARCH_X86_64_STL_UNIQUE_POINTER_HPP \ No newline at end of file
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/ext/bitfield_enum b/libs/kstd/include/kstd/ext/bitfield_enum
new file mode 100644
index 0000000..80fe9d2
--- /dev/null
+++ b/libs/kstd/include/kstd/ext/bitfield_enum
@@ -0,0 +1,65 @@
+#ifndef KSTD_EXT_BITFIELD_ENUM_HPP
+#define KSTD_EXT_BITFIELD_ENUM_HPP
+
+#include <bit>
+#include <type_traits>
+#include <utility>
+
+namespace kstd::ext
+{
+
+ template<typename EnumType>
+ requires std::is_enum_v<EnumType>
+ struct is_bitfield_enum : std::false_type
+ {
+ };
+
+ //! @concept Specifies that an enum is to be used to define bits in a bitfield.
+ template<typename EnumType>
+ concept bitfield_enum = is_bitfield_enum<EnumType>::value;
+
+}; // namespace kstd::ext
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator|(EnumType lhs, EnumType rhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(std::to_underlying(lhs) | std::to_underlying(rhs));
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator|=(EnumType & lhs, EnumType rhs) -> EnumType &
+{
+ return lhs = lhs | rhs;
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator&(EnumType lhs, EnumType rhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(std::to_underlying(lhs) & std::to_underlying(rhs));
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator&=(EnumType & lhs, EnumType rhs) -> EnumType &
+{
+ return lhs = lhs & rhs;
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator^(EnumType lhs, EnumType rhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator^=(EnumType & lhs, EnumType rhs) -> EnumType &
+{
+ return lhs = lhs ^ rhs;
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator~(EnumType lhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(~std::to_underlying(lhs));
+}
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/memory b/libs/kstd/include/kstd/memory
new file mode 100644
index 0000000..cab2fba
--- /dev/null
+++ b/libs/kstd/include/kstd/memory
@@ -0,0 +1,7 @@
+#ifndef KSTD_SHARED_POINTER_HPP
+#define KSTD_SHARED_POINTER_HPP
+
+#include "kstd/bits/shared_ptr.hpp" // IWYU pragma: export
+#include "kstd/bits/unique_ptr.hpp" // IWYU pragma: export
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/stl/mutex.hpp b/libs/kstd/include/kstd/mutex
index a7d297d..6ae3adf 100644
--- a/arch/x86_64/include/arch/stl/mutex.hpp
+++ b/libs/kstd/include/kstd/mutex
@@ -1,9 +1,9 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_MUTEX_HPP
-#define TEACHOS_ARCH_X86_64_STL_MUTEX_HPP
+#ifndef KSTD_MUTEX_HPP
+#define KSTD_MUTEX_HPP
#include <atomic>
-namespace teachos::arch::stl
+namespace kstd
{
/**
* @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in
@@ -24,12 +24,23 @@ namespace teachos::arch::stl
/**
* @brief Deleted copy constructor.
*/
- mutex(const mutex &) = delete;
+ mutex(mutex const &) = delete;
/**
- * @brief Deleted assignment operator.
+ * @brief Deleted move constructor.
+ *
+ */
+ mutex(mutex &&) = delete;
+
+ /**
+ * @brief Deleted copy assignment operator.
+ */
+ auto operator=(mutex const &) -> mutex & = delete;
+
+ /**
+ * @brief Deleted move assignment operator.
*/
- mutex & operator=(const mutex &) = delete;
+ auto operator=(mutex &&) -> mutex & = delete;
/**
* @brief Lock the mutex (blocks for as long as it is not available).
@@ -55,6 +66,6 @@ namespace teachos::arch::stl
std::atomic<bool> locked = {false}; // Atomic boolean to track if mutex is locked or not.
};
-} // namespace teachos::arch::stl
+} // namespace kstd
-#endif // TEACHOS_ARCH_X86_64_STL_MUTEX_HPP
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/libs/kstd/include/kstd/stack
index 48bcf10..8cd208a 100644
--- a/arch/x86_64/include/arch/stl/stack.hpp
+++ b/libs/kstd/include/kstd/stack
@@ -1,10 +1,10 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_STACK_HPP
-#define TEACHOS_ARCH_X86_64_STL_STACK_HPP
+#ifndef KSTD_STACK_HPP
+#define KSTD_STACK_HPP
-#include "arch/exception_handling/panic.hpp"
-#include "arch/stl/vector.hpp"
+#include "kstd/vector"
+#include <utility>
-namespace teachos::arch::stl
+namespace kstd
{
/**
* @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our
@@ -14,7 +14,7 @@ namespace teachos::arch::stl
* @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires
* access to pop_back(), push_back(), back(), size(), empty() and emplace_back()
*/
- template<typename T, typename Container = stl::vector<T>>
+ template<typename T, typename Container = kstd::vector<T>>
struct stack
{
using container_type = Container; ///< Type of the underlying container used to implement stack-like interface.
@@ -28,8 +28,12 @@ namespace teachos::arch::stl
*/
stack() = default;
+ stack(stack const &) = delete;
+ stack(stack &&) = delete;
+ auto operator=(stack const &) -> stack & = delete;
+ auto operator=(stack &&) -> stack & = delete;
/**
- * @brief Constructs data with the given amount of elements containg the given value or alterantively the default
+ * @brief Constructs data with the given amount of elements containing the given value or alternatively the default
* constructed value.
*
* @param n Amount of elements we want to create and set the given value for.
@@ -60,11 +64,11 @@ namespace teachos::arch::stl
/**
* @brief Construct data by copying all elements from the initializer list.
*
- * @param initalizer_list List we want to copy all elements from.
+ * @param elements List we want to copy all elements from.
*/
[[gnu::section(".stl_text")]]
- explicit stack(std::initializer_list<T> initalizer_list)
- : _container(initalizer_list)
+ explicit stack(std::initializer_list<T> elements)
+ : _container(elements)
{
// Nothing to do.
}
@@ -85,21 +89,6 @@ namespace teachos::arch::stl
}
/**
- * @brief Copy assignment operator.
- *
- * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all
- * elements from it.
- *
- * @param other Other instance of vector we want to copy the data from.
- * @return Newly created copy.
- */
- [[gnu::section(".stl_text")]]
- stack<T> & operator=(stack<T> const & other)
- {
- _container = other;
- }
-
- /**
* @brief Destructor.
*/
~stack() = default;
@@ -193,7 +182,7 @@ namespace teachos::arch::stl
}
/**
- * @brief Wheter there are currently any items this container or not.
+ * @brief Whether there are currently any items this container or not.
*
* @return True if there are no elements, false if there are.
*/
@@ -207,6 +196,6 @@ namespace teachos::arch::stl
container_type _container = {}; ///< Underlying container used by the stack to actually save the data.
};
-} // namespace teachos::arch::stl
+} // namespace kstd
-#endif // TEACHOS_ARCH_X86_64_STL_STACK_HPP
+#endif
diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/libs/kstd/include/kstd/vector
index 5314029..9d96eb8 100644
--- a/arch/x86_64/include/arch/stl/vector.hpp
+++ b/libs/kstd/include/kstd/vector
@@ -1,13 +1,11 @@
-#ifndef TEACHOS_ARCH_X86_64_STL_VECTOR_HPP
-#define TEACHOS_ARCH_X86_64_STL_VECTOR_HPP
+#ifndef KSTD_VECTOR_HPP
+#define KSTD_VECTOR_HPP
-#include "arch/exception_handling/panic.hpp"
-#include "arch/stl/container.hpp"
-#include "arch/stl/contiguous_pointer_iterator.hpp"
+#include "bits/os.hpp"
#include <algorithm>
-namespace teachos::arch::stl
+namespace kstd
{
/**
* @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our
@@ -31,7 +29,7 @@ namespace teachos::arch::stl
vector() = default;
/**
- * @brief Constructs data with the given amount of elements containg the given value or alterantively the default
+ * @brief Constructs data with the given amount of elements containing the given value or alternatively the default
* constructed value.
*
* @param n Amount of elements we want to create and set the given value for.
@@ -58,8 +56,7 @@ namespace teachos::arch::stl
, _capacity(std::distance(first, last))
, _data(new value_type[_capacity]{})
{
- stl::container<InputIterator> container{first, last};
- std::ranges::copy(container, _data);
+ std::ranges::copy(first, last, _data);
}
/**
@@ -102,7 +99,7 @@ namespace teachos::arch::stl
* @return Newly created copy.
*/
[[gnu::section(".stl_text")]]
- vector<value_type> & operator=(vector<value_type> const & other)
+ auto operator=(vector const & other) -> vector<value_type> &
{
delete[] _data;
_size = other._size;
@@ -115,7 +112,10 @@ namespace teachos::arch::stl
/**
* @brief Destructor.
*/
- ~vector() { delete[] _data; }
+ ~vector()
+ {
+ delete[] _data;
+ }
/**
* @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If
@@ -373,7 +373,7 @@ namespace teachos::arch::stl
[[gnu::section(".stl_text")]]
auto rend() noexcept -> pointer
{
- return _data + size - 1;
+ return _data + size() - 1;
}
/**
@@ -386,7 +386,7 @@ namespace teachos::arch::stl
[[gnu::section(".stl_text")]]
auto rend() const noexcept -> const_pointer
{
- return _data + size - 1;
+ return _data + size() - 1;
}
/**
@@ -519,8 +519,7 @@ namespace teachos::arch::stl
_capacity = new_capacity;
value_type * temp = new value_type[_capacity]{};
- stl::container<value_type *> container{begin(), end()};
- std::ranges::copy(container, temp);
+ std::ranges::copy(begin(), end(), temp);
delete[] _data;
_data = temp;
}
@@ -541,8 +540,7 @@ namespace teachos::arch::stl
_capacity = _size;
value_type * temp = new value_type[_capacity]{};
- stl::container<value_type *> container{begin(), end()};
- std::copy(container, temp);
+ std::ranges::copy(begin(), end(), temp);
delete[] _data;
_data = temp;
}
@@ -566,7 +564,7 @@ namespace teachos::arch::stl
{
if (empty())
{
- exception_handling::panic("[Vector] Attempted to access element of currently empty vector");
+ os::panic("[Vector] Attempted to access element of currently empty vector");
}
}
@@ -574,7 +572,7 @@ namespace teachos::arch::stl
{
if (index >= _size)
{
- exception_handling::panic("[Vector] Attempted to read element at invalid index");
+ os::panic("[Vector] Attempted to read element at invalid index");
}
}
@@ -596,6 +594,6 @@ namespace teachos::arch::stl
value_type * _data = {}; ///< Pointer to the first element in the underlying data container
};
-} // namespace teachos::arch::stl
+} // namespace kstd
-#endif // TEACHOS_ARCH_X86_64_STL_VECTOR_HPP
+#endif
diff --git a/libs/kstd/kstd.dox b/libs/kstd/kstd.dox
new file mode 100644
index 0000000..5920a3c
--- /dev/null
+++ b/libs/kstd/kstd.dox
@@ -0,0 +1,14 @@
+//! @namespace kstd
+//! The TeachOS Standard Library.
+//!
+//! This namespace provides implementation for Standard Library functionality that is not usually provided in a
+//! freestanding environment, since it relies on operating system support (e.g. memory allocation). The implementations
+//! found here, aim to be reasonably close to the specifications found in the C++ language standard (ISO14482).
+//! However, some differences exists, for example the lack of exceptions.
+
+//! @namespace kstd::ext
+//! Extensions to the Standard Library.
+//!
+//! This namespace includes custom extensions to what is defined for the C++ Standard Library. These extensions not
+//! portable per-se, since they are not implemented by other Standard Library implementations. Whenever possible,
+//! Standard Library conformant types, functions, etc. should be used throughout the TeachOS codebase.
diff --git a/libs/kstd/src/bits/os.cpp b/libs/kstd/src/bits/os.cpp
new file mode 100644
index 0000000..e6edbfd
--- /dev/null
+++ b/libs/kstd/src/bits/os.cpp
@@ -0,0 +1,10 @@
+#include "kstd/bits/os.hpp"
+
+namespace kstd::os
+{
+ [[gnu::weak, noreturn]]
+ auto abort() -> void
+ {
+ os::panic("Abort called.");
+ }
+} // namespace kstd::os \ No newline at end of file
diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp
new file mode 100644
index 0000000..a0f062a
--- /dev/null
+++ b/libs/kstd/src/libc/stdlib.cpp
@@ -0,0 +1,19 @@
+#include "kstd/bits/os.hpp"
+
+namespace kstd::libc
+{
+
+ extern "C"
+ {
+ [[noreturn]] auto abort() -> void
+ {
+ kstd::os::abort();
+ }
+
+ [[noreturn, gnu::weak]] auto free(void *) -> void
+ {
+ kstd::os::panic("Tried to call free.");
+ }
+ }
+
+} // namespace kstd::libc \ No newline at end of file
diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp
new file mode 100644
index 0000000..319f6fd
--- /dev/null
+++ b/libs/kstd/src/libc/string.cpp
@@ -0,0 +1,32 @@
+#include <algorithm>
+#include <bit>
+#include <cstddef>
+#include <iterator>
+#include <span>
+
+namespace kstd::libc
+{
+
+ extern "C"
+ {
+ auto strlen(char const * string) -> std::size_t
+ {
+ return std::distance(string, std::ranges::find(string, nullptr, '\0'));
+ }
+
+ auto memcmp(void const * lhs, void const * rhs, std::size_t size) -> std::size_t
+ {
+ auto left_span = std::span{static_cast<std::byte const *>(lhs), size};
+ auto right_span = std::span{static_cast<std::byte const *>(rhs), size};
+ auto mismatched = std::ranges::mismatch(left_span, right_span);
+
+ if (mismatched.in1 == left_span.end())
+ {
+ return 0;
+ }
+
+ return std::bit_cast<char>(*mismatched.in1) - std::bit_cast<char>(*mismatched.in2);
+ }
+ }
+
+} // namespace kstd::libc \ No newline at end of file
diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp
new file mode 100644
index 0000000..5a26154
--- /dev/null
+++ b/libs/kstd/src/mutex.cpp
@@ -0,0 +1,24 @@
+#include "kstd/mutex"
+
+#include <atomic>
+
+namespace kstd
+{
+ auto mutex::lock() -> void
+ {
+ while (!try_lock())
+ {
+ asm volatile("nop");
+ }
+ }
+
+ auto mutex::try_lock() -> bool
+ {
+ return !locked.exchange(true, std::memory_order_acquire);
+ }
+
+ auto mutex::unlock() -> void
+ {
+ locked.store(false, std::memory_order_release);
+ }
+} // namespace kstd
diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt
new file mode 100644
index 0000000..350a996
--- /dev/null
+++ b/libs/multiboot2/CMakeLists.txt
@@ -0,0 +1,27 @@
+add_library("multiboot2" INTERFACE)
+add_library("libs::multiboot2" ALIAS "multiboot2")
+
+target_sources("multiboot2" INTERFACE
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ "include/multiboot2/constants.hpp"
+ "include/multiboot2/information.hpp"
+
+ "include/multiboot2/impl/data.hpp"
+ "include/multiboot2/impl/ids.hpp"
+ "include/multiboot2/impl/iterator.hpp"
+ "include/multiboot2/impl/tag.hpp"
+)
+
+target_include_directories("multiboot2" INTERFACE
+ "include"
+)
+
+target_link_libraries("multiboot2" INTERFACE
+ "libs::elf"
+)
+
+set_target_properties("multiboot2" PROPERTIES
+ VERIFY_INTERFACE_HEADER_SETS YES
+) \ No newline at end of file
diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp
new file mode 100644
index 0000000..0f6b82f
--- /dev/null
+++ b/libs/multiboot2/include/multiboot2/constants.hpp
@@ -0,0 +1,20 @@
+#ifndef MULTIBOOT2_CONSTANTS_HPP
+#define MULTIBOOT2_CONSTANTS_HPP
+
+#include "impl/ids.hpp" // IWYU pragma: export
+
+#include <cstdint>
+
+namespace multiboot2
+{
+
+ using impl::architecture_id;
+ using impl::information_id;
+ using impl::memory_type;
+ using impl::tag_id;
+
+ constexpr auto inline header_magic = std::uint32_t{0xe852'50d6};
+
+} // namespace multiboot2
+
+#endif
diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp
new file mode 100644
index 0000000..733ce3a
--- /dev/null
+++ b/libs/multiboot2/include/multiboot2/impl/data.hpp
@@ -0,0 +1,135 @@
+#ifndef MULTIBOOT2_IMPL_DATA_HPP
+#define MULTIBOOT2_IMPL_DATA_HPP
+
+// IWYU pragma: private
+
+#include "multiboot2/impl/ids.hpp"
+
+#include <cstdint>
+
+namespace multiboot2::impl
+{
+ template<auto Id>
+ struct tag_data
+ {
+ constexpr auto static inline id = Id;
+ };
+
+ /**
+ * @brief Basic system memory information
+ */
+ struct basic_memory_data : tag_data<information_id::BASIC_MEMORY_INFO>
+ {
+ /**
+ * @brief Amount of lower memory (below 1MiB) available to the system.
+ *
+ * The maximum possible value for this field is 640 KiB.
+ */
+ std::uint32_t lower_KiB;
+
+ /**
+ * @brief Amount of upper memory (above 1MiB) available to the system.
+ *
+ * The maximum possible value for this field is the address of the first upper memory hole minus 1MiB.
+ */
+ std::uint32_t upper_KiB;
+ };
+
+ /**
+ * @brief Device the image got loaded from
+ */
+ struct bios_boot_device_data : tag_data<information_id::BOOTDEV>
+ {
+ /**
+ * @brief BIOS device number as understood by INT 13h.
+ */
+ std::uint32_t device_number;
+
+ /**
+ * @brief Number of the primary partition.
+ */
+ std::uint32_t partition_number;
+
+ /**
+ * @brief Number the sub-partion on the primary partition.
+ */
+ std::uint32_t sub_partition_number;
+ };
+
+ /**
+ * @brief Supplied image command line
+ */
+ struct command_line_data : tag_data<information_id::CMDLINE>
+ {
+ /* This struct intentionally left blank. */
+ };
+
+ /**
+ * @brief ELF symbols of the image
+ */
+ struct elf_symbols_data : tag_data<information_id::ELF_SECTIONS>
+ {
+ std::uint32_t count;
+ std::uint32_t entry_size;
+ std::uint32_t string_table_index;
+ };
+
+ /**
+ * @brief Name of the boot loader
+ */
+ struct loader_name_data : tag_data<information_id::BOOT_LOADER_NAME>
+ {
+ /* This struct intentionally left blank. */
+ };
+
+ /**
+ * @brief Detailed map of the memory regions present in the system
+ *
+ */
+ struct memory_map_data : tag_data<information_id::MEMORY_MAP>
+ {
+ /**
+ * @brief A region of memory
+ */
+ struct region
+ {
+ /**
+ * @brief Check if the memory described by this region is available for use.
+ */
+ [[nodiscard]] constexpr auto available() const noexcept
+ {
+ return type == memory_type::AVAILABLE;
+ }
+
+ /**
+ * @brief Start address of this region
+ */
+ std::uint64_t base;
+
+ /**
+ * @brief Size of this region in bytes.
+ */
+ std::uint64_t size_in_B;
+
+ /**
+ * @brief Type of this region.
+ */
+ memory_type type;
+
+ std::uint32_t : 0;
+ };
+
+ /**
+ * @brief Size of each entry present in the map
+ */
+ std::uint32_t entry_size;
+
+ /**
+ * @brief Version of each entry present in the map
+ */
+ std::uint32_t entry_version;
+ };
+
+} // namespace multiboot2::impl
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/libs/multiboot2/include/multiboot2/impl/ids.hpp
index a9abf12..98bc1f2 100644
--- a/arch/x86_64/include/arch/memory/multiboot/info.hpp
+++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp
@@ -1,19 +1,17 @@
-#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP
-#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP
+#ifndef MULTIBOOT2_IMPL_IDS_HPP
+#define MULTIBOOT2_IMPL_IDS_HPP
+
+// IWYU pragma: private
#include <cstdint>
-namespace teachos::arch::memory::multiboot
+namespace multiboot2::impl
{
+
/**
- * @brief Defines all possible types a multiboot2 tag structure can have.
- *
- * @note See
- * https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot2.h for more information on the structure of the
- * tag headers and see https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot.h for more information on the
- * actual header contents and their following data.
+ * @brief Information tag IDs.
*/
- enum struct tag_type : uint32_t
+ enum struct information_id : std::uint32_t
{
END, ///< Signals final tag for the multiboot2 information structure.
CMDLINE, ///< Contains the command line string.
@@ -28,37 +26,56 @@ namespace teachos::arch::memory::multiboot
APM_INFO, ///< Advanced Power Management information.
EFI32, ///< EFI 32 bit system table pointer.
EFI64, ///< EFI 64 bit system table pointer.
- SMBIOS, ///< Contains copy of all Sytem Management BIOS tables.
+ SMBIOS, ///< Contains copy of all System Management BIOS tables.
ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification.
ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification.
NETWORK, ///< Contains network information specified specified as DHCP.
EFI_MEMORY_MAP, ///< Contains EFI memory map.
- EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called.
+ EFI_BS_NOT_TERMINATED, ///< Indicates ExitBootServices wasn't called.
EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer.
- EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer.
+ EFI64_IMAGE_HANDLE, ///< EFI 64 bit image handle pointer.
LOAD_BASE_ADDRESS ///< Contains image load base physical address.
};
/**
- * @brief Basic structure that every entry in the multi_boot_tag array of the multi_boot_info struct has to begin
- * with.
+ * @brief Header tag IDs.
+ */
+ enum struct tag_id : std::uint32_t
+ {
+ END,
+ INFORMATION_REQUEST,
+ ADDRESSES,
+ ENTRY_ADDRESS,
+ CONSOLE_FLAGS,
+ PREFERRED_FRAMEBUFFER_MODE,
+ PAGE_ALIGN_MODULES,
+ EFI_BOOT_SERVICES_SUPPORTED,
+ EFI32_ENTRY_ADDRESS,
+ EFI64_ENTRY_ADDRESS,
+ RELOCATABLE,
+ };
+
+ /**
+ * @brief System architecture IDs.
*/
- struct tag
+ enum struct architecture_id : std::uint32_t
{
- tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling.
- uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type.
+ I386 = 0,
+ MIPS32 = 4,
};
/**
- * @brief Basic structure the multiboot_information_pointer points too and which contains all information of
- * multiboot2 in the tags array of different types. The start as well as the content has to be 8 byte aligned.
+ * @brief Memory type IDs.
*/
- struct info_header
+ enum struct memory_type : std::uint32_t
{
- uint32_t total_size; ///< Total size of all multiboot::tags and their data.
- alignas(8) struct tag tags; ///< Specific tags.
+ AVAILABLE = 1,
+ RESERVED,
+ ACPI_RECLAIMABLE,
+ NON_VOLATILE_STORAGE,
+ BAD_RAM,
};
-} // namespace teachos::arch::memory::multiboot
+} // namespace multiboot2::impl
-#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP
+#endif \ No newline at end of file
diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp
new file mode 100644
index 0000000..5651f22
--- /dev/null
+++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp
@@ -0,0 +1,73 @@
+#ifndef MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP
+#define MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP
+
+// IWYU pragma: private
+
+#include "multiboot2/impl/ids.hpp"
+#include "multiboot2/impl/tag.hpp"
+
+#include <cstddef>
+#include <iterator>
+#include <optional>
+
+namespace multiboot2::impl
+{
+
+ struct information_iterator
+ {
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = impl::tag_header;
+ using pointer = value_type const *;
+ using reference = value_type const &;
+ using difference_type = std::ptrdiff_t;
+
+ constexpr information_iterator() = default;
+
+ constexpr explicit information_iterator(impl::tag_header const * offset)
+ : m_current(offset)
+ {}
+
+ constexpr auto operator==(information_iterator const &) const noexcept -> bool = default;
+
+ constexpr auto operator*() const noexcept -> reference
+ {
+ return *(m_current.value());
+ }
+
+ constexpr auto operator->() const noexcept -> pointer
+ {
+ return m_current.value();
+ }
+
+ constexpr auto operator++() noexcept -> information_iterator &
+ {
+ if (m_current)
+ {
+ if (auto next = m_current.value()->next(); next->information_id() != information_id::END)
+ {
+ m_current = next;
+ }
+ else
+ {
+ m_current.reset();
+ }
+ }
+ return *this;
+ }
+
+ constexpr auto operator++(int) noexcept -> information_iterator
+ {
+ auto copy = *this;
+ ++(*this);
+ return copy;
+ }
+
+ private:
+ std::optional<impl::tag_header const *> m_current{};
+ };
+
+ static_assert(std::input_or_output_iterator<information_iterator>);
+
+} // namespace multiboot2::impl
+
+#endif \ No newline at end of file
diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp
new file mode 100644
index 0000000..3d0cea5
--- /dev/null
+++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp
@@ -0,0 +1,207 @@
+#ifndef MULTIBOOT2_IMPL_TAG_HPP
+#define MULTIBOOT2_IMPL_TAG_HPP
+
+// IWYU pragma: private
+
+#include "multiboot2/impl/ids.hpp"
+
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+
+namespace multiboot2::impl
+{
+
+ /**
+ * @brief Header data and functionality shared by all tags.
+ */
+ struct tag_header
+ {
+ tag_header()
+ : m_id{}
+ , m_size{}
+ {}
+
+ tag_header(tag_header const * data)
+ : tag_header{*data}
+ {}
+
+ [[nodiscard]] auto full_size() const noexcept -> std::size_t
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
+ return (m_size + 7) & (~7);
+ }
+
+ [[nodiscard]] auto information_id() const noexcept -> impl::information_id const &
+ {
+ return m_id;
+ }
+
+ [[nodiscard]] auto next() const noexcept -> tag_header const *
+ {
+ return std::bit_cast<tag_header const *>(std::bit_cast<std::uintptr_t>(this) + full_size());
+ }
+
+ [[nodiscard]] auto unaligned_size() const noexcept -> std::uint32_t
+ {
+ return m_size;
+ }
+
+ private:
+ impl::information_id m_id;
+ std::uint32_t m_size;
+ };
+
+ /**
+ * @brief A tag containing no variable length array data.
+ */
+ template<typename Data>
+ struct tag : tag_header, Data
+ {
+ tag()
+ : tag_header{}
+ , Data{}
+ {}
+
+ explicit tag(tag_header const * header)
+ requires(sizeof(tag) > sizeof(tag_header))
+ : tag_header{header}
+ , Data{*std::bit_cast<Data const *>(header + 1)} // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ {}
+
+ explicit tag(tag_header const * header)
+ requires(sizeof(tag) == sizeof(tag_header))
+ : tag_header{header}
+ , Data{}
+ {}
+ };
+
+ /**
+ * @brief A tag containing variable length array data.
+ */
+ template<typename Data, typename VlaData, template<typename> typename Range>
+ struct vla_tag : tag<Data>
+ {
+ using range_type = Range<VlaData const>;
+
+ using value_type = range_type::value_type;
+ using reference = range_type::const_reference;
+ using const_reference = range_type::const_reference;
+ using pointer = range_type::const_pointer;
+ using const_pointer = range_type::const_pointer;
+
+ using iterator = range_type::const_iterator;
+ using const_iterator = range_type::const_iterator;
+ using reverse_iterator = range_type::const_reverse_iterator;
+ using const_reverse_iterator = range_type::const_reverse_iterator;
+ using size_type = range_type::size_type;
+ using difference_type = range_type::difference_type;
+
+ vla_tag()
+ : tag<Data>{}
+ , m_vla{}
+ {}
+
+ explicit vla_tag(tag_header const * header)
+ : tag<Data>{header}
+ , m_vla{vla_start(header), vla_size(header)}
+ {}
+
+ [[nodiscard]] auto begin() const noexcept -> const_iterator
+ {
+ return m_vla.begin();
+ }
+
+ [[nodiscard]] auto end() const noexcept -> const_iterator
+ {
+ return m_vla.end();
+ }
+
+ [[nodiscard]] auto cbegin() const noexcept -> const_iterator
+ {
+ return begin();
+ }
+
+ [[nodiscard]] auto cend() const noexcept -> const_iterator
+ {
+ return end();
+ }
+
+ [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator
+ {
+ return m_vla.rbegin();
+ }
+
+ [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator
+ {
+ return m_vla.rend();
+ }
+
+ [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator
+ {
+ return rbegin();
+ }
+
+ [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator
+ {
+ return rend();
+ }
+
+ [[nodiscard]] auto front() const noexcept -> const_reference
+ {
+ return m_vla.front();
+ }
+
+ [[nodiscard]] auto back() const noexcept -> const_reference
+ {
+ return m_vla.back();
+ }
+
+ [[nodiscard]] auto size() const noexcept -> std::size_t
+ {
+ return m_vla.size();
+ }
+
+ [[nodiscard]] auto empty() const noexcept -> bool
+ {
+ return m_vla.empty();
+ }
+
+ [[nodiscard]] auto data() const noexcept -> const_pointer
+ {
+ return m_vla.data();
+ }
+
+ [[nodiscard]] auto at() const -> const_reference
+ {
+ return m_vla.at();
+ }
+
+ [[nodiscard]] auto operator[](std::size_t index) const noexcept -> const_reference
+ {
+ return m_vla[index];
+ }
+
+ private:
+ auto static vla_start(tag_header const * header) noexcept -> VlaData *
+ {
+ auto raw = std::bit_cast<std::uintptr_t>(header);
+ auto start = raw + sizeof(tag<Data>);
+ return std::bit_cast<VlaData *>(start);
+ }
+
+ auto static vla_size(tag_header const * header) noexcept -> std::size_t
+ {
+ auto size = (header->unaligned_size() - sizeof(tag<Data>) -
+ std::is_same_v<range_type, std::basic_string_view<VlaData>> * 1) /
+ sizeof(VlaData);
+ return size;
+ }
+
+ range_type m_vla;
+ };
+
+} // namespace multiboot2::impl
+
+#endif \ No newline at end of file
diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp
new file mode 100644
index 0000000..2d60a6d
--- /dev/null
+++ b/libs/multiboot2/include/multiboot2/information.hpp
@@ -0,0 +1,232 @@
+#ifndef JOS_MULTIBOOT2_INFORMATION_HPP
+#define JOS_MULTIBOOT2_INFORMATION_HPP
+
+#include "impl/data.hpp"
+#include "impl/iterator.hpp"
+#include "impl/tag.hpp"
+
+#include <elf/format.hpp>
+#include <elf/section_header.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <optional>
+#include <span>
+#include <string_view>
+
+namespace multiboot2
+{
+
+ /**
+ * @copydoc multiboot2::impl::basic_memory_data
+ */
+ struct basic_memory : impl::tag<impl::basic_memory_data>
+ {
+ using tag::tag;
+ };
+
+ /**
+ * @copydoc multiboot2::impl::bios_boot_device_data
+ */
+ struct bios_boot_device : impl::tag<impl::bios_boot_device_data>
+ {
+ using tag::tag;
+ };
+
+ /**
+ * @copydoc multiboot2::impl::command_line_data
+ */
+ struct command_line : impl::vla_tag<impl::command_line_data, char, std::basic_string_view>
+ {
+ using vla_tag::vla_tag;
+
+ /**
+ * @brief The command line string
+ */
+ [[nodiscard]] auto string() const noexcept -> range_type
+ {
+ return {data(), size()};
+ }
+ };
+
+ /**
+ * @copydoc multiboot2::impl::elf_symbols_data
+ */
+ template<elf::format Format>
+ struct elf_symbols : impl::vla_tag<impl::elf_symbols_data, elf::section_header<Format> const, std::span>
+ {
+ using base = impl::vla_tag<impl::elf_symbols_data, elf::section_header<Format> const, std::span>;
+ using base::base;
+
+ [[nodiscard]] auto name(elf::section_header<Format> const & section) const noexcept -> std::string_view
+ {
+ if (!this->string_table_index)
+ {
+ std::abort();
+ }
+
+ auto string_table = this->begin()[this->string_table_index];
+ auto name_offset = section.name_offset;
+ auto name_array = std::bit_cast<char const *>(string_table.virtual_load_address);
+ return name_array + name_offset;
+ }
+ };
+
+ /**
+ * @copydoc multiboot2::impl::loader_name_data
+ */
+ struct loader_name : impl::vla_tag<impl::loader_name_data, char, std::basic_string_view>
+ {
+ using vla_tag::vla_tag;
+
+ /**
+ * @brief The name of the bootloader
+ */
+ [[nodiscard]] auto string() const noexcept -> std::string_view
+ {
+ return {data(), size()};
+ }
+ };
+
+ /**
+ * @copydoc multiboot2::impl::memory_map_data
+ */
+ struct memory_map : impl::vla_tag<impl::memory_map_data, impl::memory_map_data::region, std::span>
+ {
+ using vla_tag::vla_tag;
+
+ /**
+ * @brief The available memory regions
+ */
+ [[nodiscard]] auto regions() const noexcept -> range_type
+ {
+ return {data(), size()};
+ }
+ };
+
+ struct information_view
+ {
+ using iterator = impl::information_iterator;
+ using value_type = impl::information_iterator::value_type;
+ using pointer = impl::information_iterator::pointer;
+ using reference = impl::information_iterator::reference;
+
+ [[nodiscard]] auto size_bytes() const noexcept -> std::size_t
+ {
+ return m_size;
+ }
+
+ // Range access
+
+ [[nodiscard]] auto begin() const noexcept -> iterator
+ {
+ return iterator{&m_tags};
+ }
+
+ [[nodiscard]] auto end() const noexcept -> iterator
+ {
+ return iterator{};
+ }
+
+ // Tag access
+
+ template<typename Tag>
+ [[nodiscard]] auto has() const noexcept -> bool
+ {
+ return get<Tag>().has_value();
+ }
+
+ [[nodiscard]] auto maybe_basic_memory() const noexcept -> std::optional<basic_memory>
+ {
+ return get<multiboot2::basic_memory>();
+ }
+
+ [[nodiscard]] auto basic_memory() const -> basic_memory
+ {
+ return maybe_basic_memory().value();
+ }
+
+ [[nodiscard]] auto maybe_bios_boot_device() const noexcept -> std::optional<bios_boot_device>
+ {
+ return get<multiboot2::bios_boot_device>();
+ }
+
+ [[nodiscard]] auto bios_boot_device() const -> bios_boot_device
+ {
+ return maybe_bios_boot_device().value();
+ }
+
+ [[nodiscard]] auto maybe_command_line() const noexcept -> std::optional<command_line>
+ {
+ return get<multiboot2::command_line>();
+ }
+
+ [[nodiscard]] auto command_line() const -> command_line
+ {
+ return maybe_command_line().value();
+ }
+
+ template<elf::format Format>
+ [[nodiscard]] auto maybe_elf_symbols() const noexcept -> std::optional<elf_symbols<Format>>
+ {
+ return get<multiboot2::elf_symbols<Format>>().and_then(
+ [](auto x) -> std::optional<multiboot2::elf_symbols<Format>> {
+ if (x.entry_size == elf::section_header_size<Format>)
+ {
+ return std::optional{x};
+ }
+ else
+ {
+ return std::nullopt;
+ }
+ });
+ }
+
+ template<elf::format Format>
+ [[nodiscard]] auto elf_symbols() const -> elf_symbols<Format>
+ {
+ return maybe_elf_symbols<Format>().value();
+ }
+
+ [[nodiscard]] auto maybe_loader_name() const noexcept -> std::optional<loader_name>
+ {
+ return get<multiboot2::loader_name>();
+ }
+
+ [[nodiscard]] auto loader_name() const -> loader_name
+ {
+ return maybe_loader_name().value();
+ }
+
+ [[nodiscard]] auto maybe_memory_map() const noexcept -> std::optional<memory_map>
+ {
+ return get<multiboot2::memory_map>();
+ }
+
+ [[nodiscard]] auto memory_map() const -> memory_map
+ {
+ return maybe_memory_map().value();
+ }
+
+ private:
+ template<typename Tag>
+ [[nodiscard]] constexpr auto get() const noexcept -> std::optional<Tag>
+ {
+ if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; });
+ found != end())
+ {
+ return Tag{&*found};
+ }
+ return std::nullopt;
+ }
+
+ uint32_t m_size{};
+ uint32_t : 32;
+ impl::tag_header m_tags{};
+ };
+
+} // namespace multiboot2
+
+#endif \ No newline at end of file
diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp
deleted file mode 100644
index 36c6d92..0000000
--- a/src/kernel/main.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "arch/kernel/main.hpp"
-
-#include "arch/exception_handling/panic.hpp"
-
-extern "C" auto kernel_main() -> void
-{
- teachos::arch::kernel::main();
- teachos::arch::exception_handling::panic("Architecture specific main returned!");
-}