diff options
| -rw-r--r-- | .clang-format | 163 | ||||
| -rw-r--r-- | .clang-tidy | 7 | ||||
| -rw-r--r-- | .clangd | 3 | ||||
| -rw-r--r-- | .devcontainer/x86-64/devcontainer.json | 37 | ||||
| -rw-r--r-- | .gitignore | 14 | ||||
| -rw-r--r-- | .vscode/extensions.json | 6 | ||||
| -rw-r--r-- | .vscode/launch.json | 31 | ||||
| -rw-r--r-- | .vscode/settings.json | 42 | ||||
| -rw-r--r-- | .vscode/tasks.json | 6 | ||||
| -rw-r--r-- | CMakeLists.txt | 151 | ||||
| -rw-r--r-- | CMakePresets.json | 25 | ||||
| -rw-r--r-- | Doxyfile | 2974 | ||||
| -rw-r--r-- | arch/x86_64/CMakeLists.txt | 176 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/boot/pointers.hpp | 15 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/io/port_io.hpp | 133 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/kernel/cpu/control_register.hpp | 71 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp | 67 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/concept.hpp | 21 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/physical_frame.hpp | 86 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp | 74 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/main.hpp | 30 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp | 169 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/multiboot/memory_map.hpp | 53 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/multiboot/reader.hpp | 53 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 206 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp | 39 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 180 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/page_entry.hpp | 121 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/page_table.hpp | 157 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/temporary_page.hpp | 64 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 91 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/stl/container.hpp | 99 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp | 216 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/stl/forward_value_iterator.hpp | 121 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/video/vga/io.hpp | 39 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/video/vga/text.hpp | 169 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/boot/boot.hpp | 70 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/boot/ld.hpp | 61 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/cpu/control_register.hpp | 244 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/cpu/model_specific_register.hpp | 148 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/cpu/registers.hpp | 30 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/device_io/port_io.hpp | 101 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/buffered_allocator.hpp | 68 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/kernel_mapper.hpp | 32 | ||||
| -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.hpp | 341 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/page_utilities.hpp | 22 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/paging_root.hpp | 27 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp | 23 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/region_allocator.hpp | 79 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/scoped_mapping.hpp | 66 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/vga/crtc.hpp | 39 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/vga/text.hpp | 178 | ||||
| -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.cpp | 13 | ||||
| -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.ld | 73 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/boot.s | 368 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/boot32.S | 449 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/crti.s | 13 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/crtn.s | 9 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/entry64.s | 60 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/initialize_runtime.cpp | 26 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/cio.cpp | 20 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/cpu.cpp | 12 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/memory.cpp | 193 | ||||
| -rw-r--r-- | arch/x86_64/src/kernel/cpu/control_register.cpp | 66 | ||||
| -rw-r--r-- | arch/x86_64/src/kernel/cpu/if.cpp | 7 | ||||
| -rw-r--r-- | arch/x86_64/src/kernel/cpu/tlb.cpp | 16 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/allocator/area_frame_allocator.cpp | 85 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/allocator/physical_frame.cpp | 24 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp | 34 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/kernel_mapper.cpp | 111 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/main.cpp | 77 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/mmu.cpp | 21 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp | 13 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/multiboot/reader.cpp | 131 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/page_table.cpp | 82 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/active_page_table.cpp | 98 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/inactive_page_table.cpp | 20 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/page_entry.cpp | 63 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/page_table.cpp | 128 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/temporary_page.cpp | 29 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/virtual_page.cpp | 33 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging_root.cpp | 19 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/recursive_page_mapper.cpp | 119 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/region_allocator.cpp | 92 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/scoped_mapping.cpp | 69 | ||||
| -rw-r--r-- | arch/x86_64/src/stl/mutex.cpp | 16 | ||||
| -rw-r--r-- | arch/x86_64/src/vga/text.cpp | 84 | ||||
| -rw-r--r-- | arch/x86_64/src/video/vga/text.cpp | 66 | ||||
| -rw-r--r-- | arch/x86_64/support/grub.cfg.in | 2 | ||||
| -rw-r--r-- | arch/x86_64/x86_64.dox | 14 | ||||
| -rw-r--r-- | cmake/Modules/ElfTransformations.cmake | 36 | ||||
| -rw-r--r-- | cmake/Modules/GenerateBootableIso.cmake | 22 | ||||
| -rw-r--r-- | cmake/Platforms/x86_64.cmake | 62 | ||||
| -rw-r--r-- | docs/arch.rst | 9 | ||||
| -rw-r--r-- | docs/briefs.rst | 9 | ||||
| -rw-r--r-- | docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst | 161 | ||||
| -rw-r--r-- | docs/briefs/tb0002-x86_64_bootstrap.rst | 154 | ||||
| -rw-r--r-- | docs/conf.py | 8 | ||||
| -rw-r--r-- | docs/cross.rst | 9 | ||||
| -rw-r--r-- | docs/index.rst | 3 | ||||
| -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.txt | 2 | ||||
| -rw-r--r-- | include/memory/asm_pointer.hpp | 76 | ||||
| -rw-r--r-- | kapi/CMakeLists.txt | 34 | ||||
| -rw-r--r-- | kapi/include/kapi/boot.hpp | 17 | ||||
| -rw-r--r-- | kapi/include/kapi/cio.hpp | 51 | ||||
| -rw-r--r-- | kapi/include/kapi/cio/output_device.hpp | 47 | ||||
| -rw-r--r-- | kapi/include/kapi/cpu.hpp | 13 | ||||
| -rw-r--r-- | kapi/include/kapi/memory.hpp | 70 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/address.hpp | 101 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/chunk.hpp | 104 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/frame.hpp | 39 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/frame_allocator.hpp | 43 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/page.hpp | 39 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/page_mapper.hpp | 87 | ||||
| -rw-r--r-- | kapi/include/kapi/system.hpp | 20 | ||||
| -rw-r--r-- | kernel/CMakeLists.txt | 36 | ||||
| -rw-r--r-- | kernel/src/kapi/cio.cpp | 57 | ||||
| -rw-r--r-- | kernel/src/kapi/memory.cpp | 91 | ||||
| -rw-r--r-- | kernel/src/kapi/system.cpp | 23 | ||||
| -rw-r--r-- | kernel/src/kstd.cpp | 16 | ||||
| -rw-r--r-- | kernel/src/main.cpp | 14 | ||||
| -rw-r--r-- | libs/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | libs/elf/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | libs/elf/include/elf/format.hpp | 15 | ||||
| -rw-r--r-- | libs/elf/include/elf/section_header.hpp | 99 | ||||
| -rw-r--r-- | libs/kstd/CMakeLists.txt | 40 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/asm_ptr | 77 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/os.hpp | 34 | ||||
| -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_enum | 65 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/memory | 7 | ||||
| -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.dox | 14 | ||||
| -rw-r--r-- | libs/kstd/src/bits/os.cpp | 10 | ||||
| -rw-r--r-- | libs/kstd/src/libc/stdlib.cpp | 19 | ||||
| -rw-r--r-- | libs/kstd/src/libc/string.cpp | 32 | ||||
| -rw-r--r-- | libs/kstd/src/mutex.cpp | 24 | ||||
| -rw-r--r-- | libs/multiboot2/CMakeLists.txt | 27 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/constants.hpp | 20 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/data.hpp | 135 | ||||
| -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.hpp | 73 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/tag.hpp | 207 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/information.hpp | 232 | ||||
| -rw-r--r-- | src/kernel/main.cpp | 9 |
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 @@ -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 } @@ -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!"); -} |
