From 3a2efa4ebc6b07a2304416262d5032a32dcddd8b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 13:06:17 +0000 Subject: x86_64: fix syscall error code reading --- arch/x86_64/src/context_switching/syscall/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index e291c10..b4ab468 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/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}; } -- cgit v1.2.3 From d275ced60d63b1618169d755d228a860dfd23237 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 13:06:47 +0000 Subject: memory: adapt to changes memory layout --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 81ac0cb..3afb54b 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -127,8 +127,8 @@ namespace teachos::arch::memory::paging std::array 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) + 0x217000, // .user_text (Contains the actual user code executed) + 0x21E000, // .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) -- cgit v1.2.3 From 9bfd5652e865505ae73f5ae3ba70f384d7418e84 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 13:07:01 +0000 Subject: build: upgrade x86-64 toolchain --- .vscode/launch.json | 2 +- cmake/Platforms/x86_64.cmake | 78 ++++++++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e522ad5..3b53048 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "gdbpath": "x86_64-pc-elf-gdb", "cwd": "${workspaceFolder}", "preLaunchTask": "QEMU (gdb)", - "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/_kernel", + "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/_kernel.elf", "autorun": [ "-enable-pretty-printing", "-break-insert _start" diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index e0518b5..29af020 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -1,35 +1,65 @@ -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) +include_guard(GLOBAL) -string(REGEX REPLACE "/crtbegin.o" "" CMAKE_SYSROOT "${CRT_BEGIN}") -mark_as_advanced(CMAKE_SYSROOT) +macro(find_compiler_file NAME OUTPUT_VARIABLE) + execute_process(COMMAND + "${CMAKE_CXX_COMPILER}" + "-mno-red-zone" + "-print-file-name=${NAME}" + OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE "${OUTPUT_VARIABLE}" + ERROR_QUIET + ) + mark_as_advanced("${OUTPUT_VARIABLE}") +endmacro() -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}-gcc" REQUIRED) +find_program(CMAKE_CXX_COMPILER "${CMAKE_CXX_COMPILER_TARGET}-g++" REQUIRED) + +set(CMAKE_CXX_FLAGS_INIT +"-mno-red-zone \ +-mcmodel=large \ +-fno-rtti \ +-fno-exceptions \ +-ffunction-sections \ +-fdata-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_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") + set(CMAKE_EXE_LINKER_FLAGS_INIT "-nostartfiles -Wl,--gc-sections") + +find_compiler_file("crtbegin.o" CRT_BEGIN_PATH) +find_compiler_file("crtend.o" CRT_END_PATH) + set(CMAKE_CXX_LINK_EXECUTABLE - " \ - \ - \ - \ - ${CMAKE_SYSROOT}/crtbegin.o \ - \ - -o \ - \ - -lgcc \ - ${CMAKE_SYSROOT}/crtend.o" +" \ + \ + \ + \ +${CRT_BEGIN_PATH} \ + \ +-o \ + \ +-lgcc \ +${CRT_END_PATH}" ) -- cgit v1.2.3 From 22fbbf849497c32f5b237ab70e9ed8aef63e54cf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:21:32 +0000 Subject: libs: extract multiboot library --- CMakeLists.txt | 6 + arch/x86_64/CMakeLists.txt | 4 + libs/multiboot2/CMakeLists.txt | 26 ++++ libs/multiboot2/include/multiboot2/constants.hpp | 20 +++ libs/multiboot2/include/multiboot2/impl/data.hpp | 130 +++++++++++++++++ libs/multiboot2/include/multiboot2/impl/ids.hpp | 79 ++++++++++ .../include/multiboot2/impl/iterator.hpp | 63 ++++++++ libs/multiboot2/include/multiboot2/impl/tag.hpp | 113 +++++++++++++++ libs/multiboot2/include/multiboot2/information.hpp | 160 +++++++++++++++++++++ 9 files changed, 601 insertions(+) create mode 100644 libs/multiboot2/CMakeLists.txt create mode 100644 libs/multiboot2/include/multiboot2/constants.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/data.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/ids.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/iterator.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/tag.hpp create mode 100644 libs/multiboot2/include/multiboot2/information.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c0e45f8..8fef2f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,12 @@ add_compile_options( "$<$:-pedantic-errors>" ) +#[============================================================================[ +# Global Libraries +#]============================================================================] + +add_subdirectory("libs/multiboot2" EXCLUDE_FROM_ALL SYSTEM) + #[============================================================================[ # Global Directories #]============================================================================] diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 57b3a60..bd06ea7 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -69,6 +69,10 @@ target_sources("_memory" PRIVATE "src/memory/heap/global_heap_allocator.cpp" ) +target_link_libraries("_memory" PUBLIC + "multiboot2::multiboot2" +) + #[============================================================================[ # The STL Library #]============================================================================] diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt new file mode 100644 index 0000000..af56d5a --- /dev/null +++ b/libs/multiboot2/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION "3.27") + +project("multiboot2" + LANGUAGES CXX + VERSION "1.0.0" +) + +add_library("multiboot2" INTERFACE) +add_library("multiboot2::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" +) diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp new file mode 100644 index 0000000..30d52d0 --- /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 + +namespace multiboot2 +{ + + using impl::architecture_id; + using impl::information_id; + using impl::memory_type; + using impl::tag_id; + + auto constexpr inline header_magic = std::uint32_t{0xe85250d6}; + +} // 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..367e8cb --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -0,0 +1,130 @@ +#ifndef MULTIBOOT2_IMPL_DATA_HPP +#define MULTIBOOT2_IMPL_DATA_HPP + +#include "multiboot2/impl/ids.hpp" + +#include + +namespace multiboot2::impl +{ + template + struct tag_data + { + auto constexpr inline static id = Id; + }; + + /** + * @brief Basic system memory information + */ + struct basic_memory_data : tag_data + { + /** + * @brief Amount of lower memory (below 1MiB) available to the system. + * + * The maximum possible value for this field is 640 KiB. + */ + std::uint32_t const 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 const upper_KiB; + }; + + /** + * @brief Device the image got loaded from + */ + struct bios_boot_device_data : tag_data + { + /** + * @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 + { + /* This struct intentionally left blank. */ + }; + + /** + * @brief ELF symbols of the image + */ + struct elf_symbols_data : tag_data + { + 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 + { + /* This struct intentionally left blank. */ + }; + + /** + * @brief Detailed map of the memory regions present in the system + * + */ + struct memory_map_data : tag_data + { + /** + * @brief A region of memory + */ + struct region + { + /** + * @brief Check if the memory described by this region is available for use. + */ + auto constexpr available() const noexcept { return type == memory_type::AVAILABLE; } + + /** + * @brief Start address of this region + */ + std::uint64_t const base; + + /** + * @brief Size of this region in bytes. + */ + std::uint64_t const size_in_B; + + /** + * @brief Type of this region. + */ + memory_type const type; + + std::uint32_t : 0; + }; + + /** + * @brief Size of each entry present in the map + */ + std::uint32_t const entry_size; + + /** + * @brief Version of each entry present in the map + */ + std::uint32_t const entry_version; + }; + +} // namespace multiboot2::impl + +#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/ids.hpp b/libs/multiboot2/include/multiboot2/impl/ids.hpp new file mode 100644 index 0000000..3a7215e --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp @@ -0,0 +1,79 @@ +#ifndef MULTIBOOT2_IMPL_IDS_HPP +#define MULTIBOOT2_IMPL_IDS_HPP + +#include + +namespace multiboot2::impl +{ + + /** + * @brief Information tag IDs. + */ + enum struct information_id : std::uint32_t + { + END, ///< Signals final tag for the multiboot2 information structure. + CMDLINE, ///< Contains the command line string. + BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel. + MODULE, ///< Indicates the boot module which was loaded along the kernel image. + BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address). + BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from. + MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags. + VBE_INFO, ///< Includes information to access and utilize the device GPU. + FRAMEBUFFER, ///< VBE framebuffer information. + ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel. + 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. + 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. + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. + EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer. + LOAD_BASE_ADDRESS ///< Contains image load base physical address. + }; + + /** + * @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. + */ + enum struct architecture_id : std::uint32_t + { + I386 = 0, + MIPS32 = 4, + }; + + /** + * @brief Memory type IDs. + */ + enum struct memory_type : std::uint32_t + { + AVAILABLE = 1, + RESERVED, + ACPI_RECLAIMABLE, + NON_VOLATILE_STORAGE, + BAD_RAM, + }; + +} // namespace multiboot2::impl + +#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..b84ef2c --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -0,0 +1,63 @@ +#ifndef MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP +#define MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP + +#include "multiboot2/impl/ids.hpp" +#include "multiboot2/impl/tag.hpp" + +#include +#include +#include + +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) + { + } + + auto constexpr operator==(information_iterator const &) const noexcept -> bool = default; + + auto constexpr operator*() const noexcept -> reference { return *(m_current.value()); } + + auto constexpr operator->() const noexcept -> pointer { return m_current.value(); } + + auto constexpr operator++() noexcept -> information_iterator & + { + if (m_current) + { + if (auto next = m_current.value()->next(); next->information_id() != information_id::END) + { + m_current = next; + } + m_current.reset(); + } + return *this; + } + + auto constexpr operator++(int) noexcept -> information_iterator + { + auto copy = *this; + ++(*this); + return copy; + } + + private: + std::optional m_current{}; + }; + + static_assert(std::input_or_output_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..f7471a4 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -0,0 +1,113 @@ +#ifndef MULTIBOOT2_IMPL_TAG_HPP +#define MULTIBOOT2_IMPL_TAG_HPP + +#include "multiboot2/impl/ids.hpp" + +#include +#include +#include + +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} + { + } + + auto full_size() const noexcept -> std::size_t { return (m_size + 7) & (~7); } + + auto information_id() const noexcept -> impl::information_id const & { return m_id; } + + auto next() const noexcept -> tag_header const * + { + return std::bit_cast(std::bit_cast(this) + full_size()); + } + + auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } + + protected: + impl::information_id const m_id; + std::uint32_t const m_size; + }; + + /** + * @brief A tag containing no variable length array data. + */ + template + 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(header + 1)} + { + } + + 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 Range> + struct vla_tag : tag + { + using range_type = Range; + + vla_tag() + : tag{} + , m_vla{} + { + } + + explicit vla_tag(tag_header const * header) + : tag{header} + , m_vla{vla_start(header), vla_size(header)} + { + } + + protected: + auto static vla_start(tag_header const * header) noexcept -> VlaData * + { + auto raw = std::bit_cast(header); + auto start = raw + sizeof(tag); + return std::bit_cast(start); + } + + auto static vla_size(tag_header const * header) noexcept -> std::size_t + { + auto size = (header->unaligned_size() - sizeof(tag) - + std::is_same_v> * 1) / + sizeof(VlaData); + return size; + } + + range_type const 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..04ba183 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -0,0 +1,160 @@ +#ifndef JOS_MULTIBOOT2_INFORMATION_HPP +#define JOS_MULTIBOOT2_INFORMATION_HPP + +#include "impl/data.hpp" +#include "impl/iterator.hpp" +#include "impl/tag.hpp" + +#include +#include +#include +#include +#include +#include + +namespace multiboot2 +{ + + /** + * @copydoc multiboot2::impl::basic_memory_data + */ + struct basic_memory : impl::tag + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::impl::bios_boot_device_data + */ + struct bios_boot_device : impl::tag + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::impl::command_line_data + */ + struct command_line : impl::vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The command line string + */ + auto string() const noexcept -> range_type { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::elf_symbols_data + */ + struct elf_symbols : impl::vla_tag + { + using vla_tag::vla_tag; + + using iterator = range_type::iterator; + + auto data() const noexcept -> range_type { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::loader_name_data + */ + struct loader_name : impl::vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The name of the bootloader + */ + auto string() const noexcept -> std::string_view { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::memory_map_data + */ + struct memory_map : impl::vla_tag + { + using vla_tag::vla_tag; + + using iterator = range_type::iterator; + + auto begin() const noexcept -> iterator { return regions().begin(); } + + auto end() const noexcept -> iterator { return regions().end(); } + + /** + * @brief The available memory regions + */ + auto regions() const noexcept -> range_type { return m_vla; } + }; + + 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; + + auto size_bytes() const noexcept -> std::size_t { return m_size; } + + // Range access + + auto begin() const noexcept -> iterator { return iterator{&m_tags}; } + + auto end() const noexcept -> iterator { return iterator{}; } + + // Tag access + + template + auto has() const noexcept -> bool + { + return get().has_value(); + } + + auto maybe_basic_memory() const noexcept -> std::optional { return get(); } + + auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } + + auto maybe_bios_boot_device() const noexcept -> std::optional + { + return get(); + } + + auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } + + auto maybe_command_line() const noexcept -> std::optional { return get(); } + + auto command_line() const -> command_line { return maybe_command_line().value(); } + + auto maybe_elf_symbols() const noexcept -> std::optional { return get(); } + + auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } + + auto maybe_loader_name() const noexcept -> std::optional { return get(); } + + auto loader_name() const -> loader_name { return maybe_loader_name().value(); } + + auto maybe_memory_map() const noexcept -> std::optional { return get(); } + + auto memory_map() const -> memory_map { return maybe_memory_map().value(); } + + private: + template + auto constexpr get() const noexcept -> std::optional + { + if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); + found != end()) + { + return Tag{&*found}; + } + return std::nullopt; + } + + [[maybe_unused]] uint32_t const m_size{}; + uint32_t : 32; + impl::tag_header const m_tags{}; + }; + +} // namespace multiboot2 + +#endif \ No newline at end of file -- cgit v1.2.3 From e7eedd234954509f4f5ec52b2d62cbc4a1723936 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:39:09 +0000 Subject: libs: begin extraction of kernel std --- CMakeLists.txt | 9 +- arch/x86_64/CMakeLists.txt | 13 +- .../arch/memory/heap/linked_list_allocator.hpp | 5 +- .../arch/memory/heap/user_heap_allocator.hpp | 5 +- .../arch/memory/multiboot/elf_symbols_section.hpp | 41 ++-- arch/x86_64/include/arch/memory/multiboot/info.hpp | 64 ------ .../include/arch/memory/multiboot/memory_map.hpp | 53 ----- .../include/arch/memory/multiboot/reader.hpp | 19 +- arch/x86_64/include/arch/stl/mutex.hpp | 60 ----- .../src/memory/heap/linked_list_allocator.cpp | 2 +- arch/x86_64/src/memory/multiboot/reader.cpp | 250 +++++++++++---------- arch/x86_64/src/stl/mutex.cpp | 16 -- libs/kstd/CMakeLists.txt | 24 ++ libs/kstd/include/kstd/mutex.hpp | 60 +++++ libs/kstd/src/mutex.cpp | 16 ++ 15 files changed, 273 insertions(+), 364 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/multiboot/info.hpp delete mode 100644 arch/x86_64/include/arch/memory/multiboot/memory_map.hpp delete mode 100644 arch/x86_64/include/arch/stl/mutex.hpp delete mode 100644 arch/x86_64/src/stl/mutex.cpp create mode 100644 libs/kstd/CMakeLists.txt create mode 100644 libs/kstd/include/kstd/mutex.hpp create mode 100644 libs/kstd/src/mutex.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fef2f5..75ac1b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,7 @@ add_compile_options( # Global Libraries #]============================================================================] +add_subdirectory("libs/kstd" EXCLUDE_FROM_ALL SYSTEM) add_subdirectory("libs/multiboot2" EXCLUDE_FROM_ALL SYSTEM) #[============================================================================[ @@ -133,13 +134,6 @@ add_library("teachos::interrupt_handling" ALIAS "_interrupt_handling") # 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 #]============================================================================] @@ -154,7 +148,6 @@ target_link_libraries("_kernel" PRIVATE "teachos::video" "teachos::memory" "teachos::exception" - "teachos::stl" "teachos::context_switching" "teachos::interrupt_handling" ) diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index bd06ea7..511fe43 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -71,14 +71,7 @@ target_sources("_memory" PRIVATE target_link_libraries("_memory" PUBLIC "multiboot2::multiboot2" -) - -#[============================================================================[ -# The STL Library -#]============================================================================] - -target_sources("_stl" PRIVATE - "src/stl/mutex.cpp" + "libs::kstd" ) #[============================================================================[ @@ -115,6 +108,10 @@ target_sources("_context" PRIVATE "src/context_switching/interrupt_descriptor_table/segment_selector.cpp" ) +target_link_libraries("_context" PUBLIC + "libs::kstd" +) + #[============================================================================[ # The Interrupt Handlers #]============================================================================] diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 582b4af..bbbad19 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/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 namespace teachos::arch::memory::heap { @@ -112,7 +113,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/user_heap_allocator.hpp b/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp index 6b1b7bb..3b47f15 100644 --- a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp @@ -2,8 +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 +#include #include namespace teachos::arch::memory::heap @@ -141,7 +142,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/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index 0a25ca9..348c159 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -1,9 +1,9 @@ #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 "arch/memory/multiboot/info.hpp" +// #include "arch/stl/container.hpp" +// #include "arch/stl/contiguous_pointer_iterator.hpp" #include #include @@ -145,24 +145,25 @@ namespace teachos::arch::memory::multiboot 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. - }; + // /** + // * @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>; + // using elf_section_header_container = stl::container>; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/arch/x86_64/include/arch/memory/multiboot/info.hpp deleted file mode 100644 index a9abf12..0000000 --- a/arch/x86_64/include/arch/memory/multiboot/info.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP - -#include - -namespace teachos::arch::memory::multiboot -{ - /** - * @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. - */ - enum struct tag_type : uint32_t - { - END, ///< Signals final tag for the multiboot2 information structure. - CMDLINE, ///< Contains the command line string. - BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel. - MODULE, ///< Indicates the boot module which was loaded along the kernel image. - BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address). - BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from. - MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags. - VBE_INFO, ///< Includes information to access and utilize the device GPU. - FRAMEBUFFER, ///< VBE framebuffer information. - ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel. - 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. - 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. - EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. - EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae 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. - */ - struct tag - { - 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. - }; - - /** - * @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. - */ - struct info_header - { - uint32_t total_size; ///< Total size of all multiboot::tags and their data. - alignas(8) struct tag tags; ///< Specific tags. - }; - -} // namespace teachos::arch::memory::multiboot - -#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_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 - -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>; - -} // 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 index bda0c43..c5464cb 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -1,10 +1,14 @@ #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 "arch/memory/multiboot/elf_symbols_section.hpp" -#include "arch/memory/multiboot/memory_map.hpp" #include +#include +#include namespace teachos::arch::memory::multiboot { @@ -14,12 +18,13 @@ namespace teachos::arch::memory::multiboot */ 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. + 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. + multiboot2::elf_symbols; ///< 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. + // std::sp + // memory_area_container areas; ///< Contains non-owning pointers to all memory areas. }; /** diff --git a/arch/x86_64/include/arch/stl/mutex.hpp b/arch/x86_64/include/arch/stl/mutex.hpp deleted file mode 100644 index a7d297d..0000000 --- a/arch/x86_64/include/arch/stl/mutex.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_STL_MUTEX_HPP -#define TEACHOS_ARCH_X86_64_STL_MUTEX_HPP - -#include - -namespace teachos::arch::stl -{ - /** - * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in - * use by another thread or not. - */ - struct mutex - { - /** - * @brief Defaulted constructor. - */ - mutex() = default; - - /** - * @brief Defaulted destructor. - */ - ~mutex() = default; - - /** - * @brief Deleted copy constructor. - */ - mutex(const mutex &) = delete; - - /** - * @brief Deleted assignment operator. - */ - mutex & operator=(const mutex &) = delete; - - /** - * @brief Lock the mutex (blocks for as long as it is not available). - */ - [[gnu::section(".stl_text")]] - auto lock() -> void; - - /** - * @brief Try to lock the mutex (non-blocking). - * - * @return True if lock has been acquired and false otherwise. - */ - [[gnu::section(".stl_text")]] - auto try_lock() -> bool; - - /** - * @brief Unlock the mutex. - */ - [[gnu::section(".stl_text")]] - auto unlock() -> void; - - private: - std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. - }; - -} // namespace teachos::arch::stl - -#endif // TEACHOS_ARCH_X86_64_STL_MUTEX_HPP diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/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/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/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 2bf5b25..b05e6b3 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -2,130 +2,134 @@ #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 "multiboot2/information.hpp" +// #include "arch/memory/multiboot/elf_symbols_section.hpp" +// #include "arch/memory/multiboot/info.hpp" #include #include -namespace teachos::arch::memory::multiboot -{ - namespace - { - template - requires std::is_pointer::value - auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T - { - return reinterpret_cast(reinterpret_cast(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(&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(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(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(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 +// namespace teachos::arch::memory::multiboot +// { +// namespace +// { +// template +// requires std::is_pointer::value +// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T +// { +// return reinterpret_cast(reinterpret_cast(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(&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(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(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(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/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/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt new file mode 100644 index 0000000..06083f3 --- /dev/null +++ b/libs/kstd/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION "3.27") + +project("kstd" + LANGUAGES CXX + VERSION "1.0.0" +) + +add_library("kstd" STATIC) +add_library("libs::kstd" ALIAS "kstd") + +target_sources("kstd" PRIVATE + "src/mutex.cpp" +) + +target_sources("kstd" PUBLIC + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/kstd/mutex.hpp" +) + +target_include_directories("kstd" PUBLIC + "include" +) diff --git a/libs/kstd/include/kstd/mutex.hpp b/libs/kstd/include/kstd/mutex.hpp new file mode 100644 index 0000000..cf8549f --- /dev/null +++ b/libs/kstd/include/kstd/mutex.hpp @@ -0,0 +1,60 @@ +#ifndef KSTD_MUTEX_HPP +#define KSTD_MUTEX_HPP + +#include + +namespace kstd +{ + /** + * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in + * use by another thread or not. + */ + struct mutex + { + /** + * @brief Defaulted constructor. + */ + mutex() = default; + + /** + * @brief Defaulted destructor. + */ + ~mutex() = default; + + /** + * @brief Deleted copy constructor. + */ + mutex(const mutex &) = delete; + + /** + * @brief Deleted assignment operator. + */ + mutex & operator=(const mutex &) = delete; + + /** + * @brief Lock the mutex (blocks for as long as it is not available). + */ + [[gnu::section(".stl_text")]] + auto lock() -> void; + + /** + * @brief Try to lock the mutex (non-blocking). + * + * @return True if lock has been acquired and false otherwise. + */ + [[gnu::section(".stl_text")]] + auto try_lock() -> bool; + + /** + * @brief Unlock the mutex. + */ + [[gnu::section(".stl_text")]] + auto unlock() -> void; + + private: + std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. + }; + +} // namespace kstd + +#endif \ 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..cfb1c84 --- /dev/null +++ b/libs/kstd/src/mutex.cpp @@ -0,0 +1,16 @@ +#include "kstd/mutex.hpp" + +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 -- cgit v1.2.3 From 1b603d1145b9ee10b1b12a0f765bd2bc1ebe2b3c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:39:59 +0000 Subject: libs: rename multiboot alias --- arch/x86_64/CMakeLists.txt | 2 +- libs/multiboot2/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 511fe43..c8ff216 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -70,8 +70,8 @@ target_sources("_memory" PRIVATE ) target_link_libraries("_memory" PUBLIC - "multiboot2::multiboot2" "libs::kstd" + "libs::multiboot2" ) #[============================================================================[ diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index af56d5a..386a127 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -6,7 +6,7 @@ project("multiboot2" ) add_library("multiboot2" INTERFACE) -add_library("multiboot2::multiboot2" ALIAS "multiboot2") +add_library("libs::multiboot2" ALIAS "multiboot2") target_sources("multiboot2" INTERFACE FILE_SET HEADERS -- cgit v1.2.3 From 25483b7af8df6b08d460f807fda04c6d409bd44e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:02:43 +0000 Subject: ide: start large-scale restructuring --- CMakeLists.txt | 268 +++++++++++++++++++++++-------------------- arch/CMakeLists.txt | 17 +++ arch/include/arch/io.hpp | 9 ++ arch/include/arch/memory.hpp | 9 ++ arch/include/arch/system.hpp | 9 ++ cmake/Platforms/x86_64.cmake | 1 - kern/CMakeLists.txt | 16 +++ kern/include/kern/error.hpp | 13 +++ kern/include/kern/print.hpp | 26 +++++ kern/src/abort.cpp | 3 + kern/src/error.cpp | 19 +++ kern/src/main.cpp | 11 ++ kern/src/print.cpp | 76 ++++++++++++ libs/CMakeLists.txt | 2 + src/kernel/main.cpp | 9 -- 15 files changed, 352 insertions(+), 136 deletions(-) create mode 100644 arch/CMakeLists.txt create mode 100644 arch/include/arch/io.hpp create mode 100644 arch/include/arch/memory.hpp create mode 100644 arch/include/arch/system.hpp create mode 100644 kern/CMakeLists.txt create mode 100644 kern/include/kern/error.hpp create mode 100644 kern/include/kern/print.hpp create mode 100644 kern/src/abort.cpp create mode 100644 kern/src/error.cpp create mode 100644 kern/src/main.cpp create mode 100644 kern/src/print.cpp create mode 100644 libs/CMakeLists.txt delete mode 100644 src/kernel/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 75ac1b5..e10da55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,138 +22,154 @@ 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( - "$<$:-Wall>" - "$<$:-Wextra>" - "$<$:-Werror>" - "$<$:-pedantic-errors>" -) - -#[============================================================================[ -# Global Libraries +# Global Build System Configuration #]============================================================================] -add_subdirectory("libs/kstd" EXCLUDE_FROM_ALL SYSTEM) -add_subdirectory("libs/multiboot2" EXCLUDE_FROM_ALL SYSTEM) +add_subdirectory("libs") +add_subdirectory("kern") +add_subdirectory("arch") -#[============================================================================[ -# Global Directories -#]============================================================================] +add_executable("kernel") -include_directories( - "include" - "arch/${CMAKE_SYSTEM_PROCESSOR}/include" +target_link_libraries("kernel" PRIVATE + "kern" + "arch::all" + # "arch-${CMAKE_SYSTEM_PROCESSOR}" ) -#[============================================================================[ -# The Bootstrap Library -#]============================================================================] +# #[============================================================================[ +# # Documentation +# #]============================================================================] -add_library("_boot" OBJECT) -add_library("teachos::boot" ALIAS "_boot") +# find_package("Doxygen") -#[============================================================================[ -# The Video Library -#]============================================================================] - -add_library("_video" OBJECT) -add_library("teachos::video" ALIAS "_video") - -#[============================================================================[ -# THE Memory Library -#]============================================================================] - -add_library("_memory" OBJECT) -add_library("teachos::memory" ALIAS "_memory") - -#[============================================================================[ -# The Exception handling Library -#]============================================================================] - -add_library("_exception" OBJECT) -add_library("teachos::exception" ALIAS "_exception") - -#[============================================================================[ -# 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 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::context_switching" - "teachos::interrupt_handling" -) - -#[============================================================================[ -# Platform Specific Components -#]============================================================================] +# 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") -add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") +# 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( +# "$<$:-Wall>" +# "$<$:-Wextra>" +# "$<$:-Werror>" +# "$<$:-pedantic-errors>" +# ) + +# #[============================================================================[ +# # Global Libraries +# #]============================================================================] + +# add_subdirectory("libs/kstd" EXCLUDE_FROM_ALL SYSTEM) +# add_subdirectory("libs/multiboot2" EXCLUDE_FROM_ALL SYSTEM) + +# #[============================================================================[ +# # 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 +# #]============================================================================] + +# add_library("_video" OBJECT) +# add_library("teachos::video" ALIAS "_video") + +# #[============================================================================[ +# # THE Memory Library +# #]============================================================================] + +# add_library("_memory" OBJECT) +# add_library("teachos::memory" ALIAS "_memory") + +# #[============================================================================[ +# # The Exception handling Library +# #]============================================================================] + +# add_library("_exception" OBJECT) +# add_library("teachos::exception" ALIAS "_exception") + +# #[============================================================================[ +# # 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 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::context_switching" +# "teachos::interrupt_handling" +# ) + +# #[============================================================================[ +# # Platform Specific Components +# #]============================================================================] + +# add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt new file mode 100644 index 0000000..3bdc3c2 --- /dev/null +++ b/arch/CMakeLists.txt @@ -0,0 +1,17 @@ +add_library("arch-all" INTERFACE) +add_library("arch::all" ALIAS "arch-all") + +target_sources("arch-all" INTERFACE + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/arch/io.hpp" + "include/arch/memory.hpp" + "include/arch/system.hpp" +) + +target_include_directories("arch-all" INTERFACE + "include" +) + +# add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") diff --git a/arch/include/arch/io.hpp b/arch/include/arch/io.hpp new file mode 100644 index 0000000..8986b9c --- /dev/null +++ b/arch/include/arch/io.hpp @@ -0,0 +1,9 @@ +#ifndef TEACHOS_ARCH_IO_HPP +#define TEACHOS_ARCH_IO_HPP + +namespace teachos::arch::io +{ + auto init() -> void; +} + +#endif diff --git a/arch/include/arch/memory.hpp b/arch/include/arch/memory.hpp new file mode 100644 index 0000000..33f7fdd --- /dev/null +++ b/arch/include/arch/memory.hpp @@ -0,0 +1,9 @@ +#ifndef TEACHOS_ARCH_MEMORY_HPP +#define TEACHOS_ARCH_MEMORY_HPP + +namespace teachos::arch::memory +{ + auto init() -> void; +} + +#endif diff --git a/arch/include/arch/system.hpp b/arch/include/arch/system.hpp new file mode 100644 index 0000000..73e2463 --- /dev/null +++ b/arch/include/arch/system.hpp @@ -0,0 +1,9 @@ +#ifndef TEACHOS_ARCH_SYSTEM_HPP +#define TEACHOS_ARCH_SYSTEM_HPP + +namespace teachos::arch::system +{ + [[noreturn]] auto halt() -> void; +} + +#endif diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index 29af020..c84d9ba 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -60,6 +60,5 @@ ${CRT_BEGIN_PATH} \ \ -o \ \ --lgcc \ ${CRT_END_PATH}" ) diff --git a/kern/CMakeLists.txt b/kern/CMakeLists.txt new file mode 100644 index 0000000..b2c7e2f --- /dev/null +++ b/kern/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library("kern" OBJECT + "src/abort.cpp" + "src/error.cpp" + "src/main.cpp" + "src/print.cpp" +) + +target_include_directories("kern" PUBLIC + "include" +) + +target_link_libraries("kern" PUBLIC + "arch::all" + + "gcc" +) diff --git a/kern/include/kern/error.hpp b/kern/include/kern/error.hpp new file mode 100644 index 0000000..e58b9f1 --- /dev/null +++ b/kern/include/kern/error.hpp @@ -0,0 +1,13 @@ +#ifndef TEACHOS_KERN_ERROR_HPP +#define TEACHOS_KERN_ERROR_HPP + +#include +#include + +namespace teachos +{ + [[noreturn]] + auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; +} + +#endif diff --git a/kern/include/kern/print.hpp b/kern/include/kern/print.hpp new file mode 100644 index 0000000..fc9b5d6 --- /dev/null +++ b/kern/include/kern/print.hpp @@ -0,0 +1,26 @@ + +#ifndef TEACHOS_KERN_PRINT_HPP +#define TEACHOS_KERN_PRINT_HPP + +#include + +namespace teachos +{ + + using print_handler = auto(std::string_view) -> void; + using println_handler = auto(std::string_view) -> void; + + auto print(std::string_view text) -> void; + auto println(std::string_view text) -> void; + + auto print_error(std::string_view text) -> void; + auto println_error(std::string_view text) -> void; + + auto set_print_handler(print_handler handler) -> print_handler *; + auto set_println_handler(println_handler handler) -> print_handler *; + auto set_print_error_handler(print_handler handler) -> print_handler *; + auto set_println_error_handler(println_handler handler) -> print_handler *; + +} // namespace teachos + +#endif diff --git a/kern/src/abort.cpp b/kern/src/abort.cpp new file mode 100644 index 0000000..6db0b74 --- /dev/null +++ b/kern/src/abort.cpp @@ -0,0 +1,3 @@ +#include "kern/error.hpp" + +extern "C" [[noreturn]] auto abort() -> void { teachos::panic("Abort called"); } diff --git a/kern/src/error.cpp b/kern/src/error.cpp new file mode 100644 index 0000000..a5229fd --- /dev/null +++ b/kern/src/error.cpp @@ -0,0 +1,19 @@ +#include "kern/error.hpp" + +#include "arch/system.hpp" +#include "kern/print.hpp" + +namespace teachos +{ + + auto panic(std::string_view message, std::source_location location) -> void + { + println_error("!!!Kernel Panic!!! "); + println_error(message); + println_error(location.file_name()); + println_error(location.function_name()); + + arch::system::halt(); + } + +} // namespace teachos diff --git a/kern/src/main.cpp b/kern/src/main.cpp new file mode 100644 index 0000000..5e1b6ea --- /dev/null +++ b/kern/src/main.cpp @@ -0,0 +1,11 @@ +#include "arch/io.hpp" +#include "arch/memory.hpp" +#include "kern/error.hpp" + +auto main() -> int +{ + teachos::arch::io::init(); + teachos::arch::memory::init(); + + teachos::panic("Architecture specific main returned!"); +} diff --git a/kern/src/print.cpp b/kern/src/print.cpp new file mode 100644 index 0000000..64e2c65 --- /dev/null +++ b/kern/src/print.cpp @@ -0,0 +1,76 @@ + +#include "kern/print.hpp" + +#include + +namespace teachos +{ + namespace + { + print_handler * current_print_handler{}; + println_handler * current_println_handler{}; + print_handler * current_print_error_handler{}; + println_handler * current_println_error_handler{}; + } // namespace + + auto print(std::string_view text) -> void + { + if (current_print_handler) + { + current_print_handler(text); + } + } + + auto println(std::string_view text) -> void + { + if (current_println_handler) + { + current_println_handler(text); + } + } + + auto print_error(std::string_view text) -> void + { + if (current_print_error_handler) + { + current_print_error_handler(text); + } + } + + auto println_error(std::string_view text) -> void + { + if (current_println_error_handler) + { + current_println_error_handler(text); + } + } + + auto set_print_handler(print_handler handler) -> print_handler * + { + auto old = current_print_handler; + current_print_handler = handler; + return old; + } + + auto set_println_handler(println_handler handler) -> print_handler * + { + auto old = current_println_handler; + current_println_handler = handler; + return old; + } + + auto set_print_error_handler(print_handler handler) -> print_handler * + { + auto old = current_print_error_handler; + current_print_error_handler = handler; + return old; + } + + auto set_println_error_handler(println_handler handler) -> print_handler * + { + auto old = current_println_error_handler; + current_println_error_handler = handler; + return old; + } + +} // namespace teachos diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt new file mode 100644 index 0000000..b2dbf86 --- /dev/null +++ b/libs/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory("kstd" EXCLUDE_FROM_ALL SYSTEM) +add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) \ 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!"); -} -- cgit v1.2.3 From ec572bff8150e2f8cd2dc99e053c5e8c8a0b99e3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:25:00 +0000 Subject: arch: prepare interfaces --- CMakeLists.txt | 8 +- arch/CMakeLists.txt | 10 +- arch/x86_64/CMakeLists.txt | 314 +++++++++++++++++++++++------------------ arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/io.cpp | 22 +++ arch/x86_64/src/memory.cpp | 62 ++++++++ arch/x86_64/src/system.cpp | 12 ++ kern/CMakeLists.txt | 2 +- libs/kstd/CMakeLists.txt | 7 - libs/multiboot2/CMakeLists.txt | 7 - 10 files changed, 285 insertions(+), 161 deletions(-) create mode 100644 arch/x86_64/src/io.cpp create mode 100644 arch/x86_64/src/memory.cpp create mode 100644 arch/x86_64/src/system.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e10da55..c08753b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,16 +25,16 @@ set(CMAKE_CXX_EXTENSIONS NO) # Global Build System Configuration #]============================================================================] +add_executable("kernel") + add_subdirectory("libs") add_subdirectory("kern") add_subdirectory("arch") -add_executable("kernel") - target_link_libraries("kernel" PRIVATE "kern" - "arch::all" - # "arch-${CMAKE_SYSTEM_PROCESSOR}" + "arch::any" + "arch::${CMAKE_SYSTEM_PROCESSOR}" ) # #[============================================================================[ diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt index 3bdc3c2..c7b2c15 100644 --- a/arch/CMakeLists.txt +++ b/arch/CMakeLists.txt @@ -1,7 +1,7 @@ -add_library("arch-all" INTERFACE) -add_library("arch::all" ALIAS "arch-all") +add_library("arch-any" INTERFACE) +add_library("arch::any" ALIAS "arch-any") -target_sources("arch-all" INTERFACE +target_sources("arch-any" INTERFACE FILE_SET HEADERS BASE_DIRS "include" FILES @@ -10,8 +10,8 @@ target_sources("arch-all" INTERFACE "include/arch/system.hpp" ) -target_include_directories("arch-all" INTERFACE +target_include_directories("arch-any" INTERFACE "include" ) -# add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") +add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index c8ff216..19bc78c 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -1,156 +1,198 @@ -#[============================================================================[ -# The Kernel Library -#]============================================================================] - -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}" -) - -set_target_properties("_kernel" PROPERTIES - LINK_DEPENDS "${TEACHOS_KERNEL_LINKER_SCRIPT}" -) +add_library("arch-x86_64" OBJECT) +add_library("arch::x86_64" ALIAS "arch-x86_64") -#[============================================================================[ -# The Bootstrap Library -#]============================================================================] - -target_sources("_boot" PRIVATE - "src/boot/boot.s" - "src/boot/crti.s" - "src/boot/crtn.s" - "src/boot/multiboot.s" +target_include_directories("arch-x86_64" PUBLIC + "include" ) -#[============================================================================[ -# The Video Library -#]============================================================================] +target_link_libraries("arch-x86_64" PUBLIC + "kern" -target_sources("_video" PRIVATE - "src/video/vga/text.cpp" + "libs::multiboot2" ) -#[============================================================================[ -# The Memory Library -#]============================================================================] - -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_link_options("arch-x86_64" PUBLIC + "-T${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" ) -target_link_libraries("_memory" PUBLIC - "libs::kstd" - "libs::multiboot2" +set_target_properties("arch-x86_64" PROPERTIES + LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" ) #[============================================================================[ -# The Exception handling Library +# arch::any Implementation #]============================================================================] -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" +target_sources("arch-x86_64" PRIVATE + "src/io.cpp" + "src/memory.cpp" + "src/system.cpp" ) #[============================================================================[ -# The Context switching Library +# Bootstrap Code #]============================================================================] -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" +target_sources("arch-x86_64" PRIVATE + "src/boot/boot.s" + "src/boot/crti.s" + "src/boot/crtn.s" + "src/boot/multiboot.s" ) -target_link_libraries("_context" PUBLIC - "libs::kstd" -) - -#[============================================================================[ -# 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-$.iso" - "${CMAKE_CURRENT_BINARY_DIR}/isofs" - "$" - "2>/dev/null" - DEPENDS - "$" - "isofs/boot/grub/grub.cfg" - BYPRODUCTS "${PROJECT_BINARY_DIR}/teachos-$.iso" - COMMENT "Creating bootable ISO image" - ) -endif() +# #[============================================================================[ +# # The Kernel Library +# #]============================================================================] + +# 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}" +# ) + +# set_target_properties("_kernel" PROPERTIES +# LINK_DEPENDS "${TEACHOS_KERNEL_LINKER_SCRIPT}" +# ) + +# #[============================================================================[ +# # The Bootstrap Library +# #]============================================================================] + +# target_sources("_boot" PRIVATE +# "src/boot/boot.s" +# "src/boot/crti.s" +# "src/boot/crtn.s" +# "src/boot/multiboot.s" +# ) + +# #[============================================================================[ +# # The Video Library +# #]============================================================================] + +# target_sources("_video" PRIVATE +# "src/video/vga/text.cpp" +# ) + +# #[============================================================================[ +# # The Memory Library +# #]============================================================================] + +# 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_link_libraries("_memory" PUBLIC +# "libs::kstd" +# "libs::multiboot2" +# ) + +# #[============================================================================[ +# # 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" +# ) + +# target_link_libraries("_context" PUBLIC +# "libs::kstd" +# ) + +# #[============================================================================[ +# # 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-$.iso" +# "${CMAKE_CURRENT_BINARY_DIR}/isofs" +# "$" +# "2>/dev/null" +# DEPENDS +# "$" +# "isofs/boot/grub/grub.cfg" +# BYPRODUCTS "${PROJECT_BINARY_DIR}/teachos-$.iso" +# COMMENT "Creating bootable ISO image" +# ) +# endif() diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..5488073 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -364,5 +364,5 @@ _transition_to_long_mode: call _init - call kernel_main + call main call halt diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp new file mode 100644 index 0000000..8808dbb --- /dev/null +++ b/arch/x86_64/src/io.cpp @@ -0,0 +1,22 @@ +namespace teachos::arch::io +{ + + // using x86_64::vga::text_mode::attributes; + // using x86_64::vga::text_mode::color; + + // namespace + // { + // auto constexpr error_attributes = + // attributes{.foreground = color::light_gray, .bright = true, .background = color::red, .blink = true}; + // } // namespace + + auto init() -> void + { + // kernel::set_print_handler([](auto text) { return x86_64::vga::text_mode::print(text); }); + // kernel::set_println_handler([](auto text) { return x86_64::vga::text_mode::println(text); }); + // kernel::set_print_error_handler([](auto text) { return x86_64::vga::text_mode::print(text, error_attributes); }); + // kernel::set_println_error_handler( + // [](auto text) { return x86_64::vga::text_mode::println(text, error_attributes); }); + } + +} // namespace teachos::arch::io diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp new file mode 100644 index 0000000..245d7bd --- /dev/null +++ b/arch/x86_64/src/memory.cpp @@ -0,0 +1,62 @@ +#include "arch/memory.hpp" + +// #include "noarch/error.hpp" +// #include "noarch/print.hpp" +// #include "x86_64/bootstrap/mutiboot.hpp" +// #include "x86_64/memory/frame_allocator.hpp" +// #include "x86_64/memory/mbi_frame_allocator.hpp" + +// #include +// #include +// #include +// #include + +namespace teachos::arch::memory +{ + + // namespace + // { + // /** + // * @brief Remap the kernel according to the ELF information. + // * + // * After initial bootup, a basic identity mapping of the lower 1GiB is set up. This mapping allows execution + // from, + // * as well as read and write access to, the mapped memory. In order to protect the kernel, remap it according to + // the + // * information supplied by the ELF file. This means remapping code sections as read-only and data sections as + // * no-execute (and read only for .rodata). + // * + // * @param sections Information about the sections in the loaded kernel binary. + // * @param allocator The frame allocator used to create new page mappings. + // */ + // auto remap_kernel(elf::section_header_table const & sections, x86_64::memory::frame_allocator & allocator) -> + // void + // { + // static_cast(sections); + // static_cast(allocator); + // } + // } // namespace + + auto init() -> void + { + // kernel::println("Initializing memory"); + + // if (!x86_64::bootstrap::multiboot_information_pointer->has()) + // { + // kernel::panic("Received no memory map from the boot loader!"); + // } + + // if (!x86_64::bootstrap::multiboot_information_pointer->has()) + // { + // kernel::panic("Received no ELF symbol information from the boot loader!"); + // } + + // auto memory_map = x86_64::bootstrap::multiboot_information_pointer->memory_map(); + // auto elf_symbols = x86_64::bootstrap::multiboot_information_pointer->elf_symbols(); + // auto section_header_table = elf::section_header_table{elf_symbols.data(), elf::file_class::bits_64}; + // auto allocator = x86_64::memory::mbi_frame_allocator{memory_map, section_header_table}; + + // remap_kernel(section_header_table, allocator); + } + +} // namespace teachos::arch::memory diff --git a/arch/x86_64/src/system.cpp b/arch/x86_64/src/system.cpp new file mode 100644 index 0000000..60ebf0e --- /dev/null +++ b/arch/x86_64/src/system.cpp @@ -0,0 +1,12 @@ +#include "arch/system.hpp" + +namespace teachos::arch::system +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace teachos::arch::system diff --git a/kern/CMakeLists.txt b/kern/CMakeLists.txt index b2c7e2f..9bfe9e8 100644 --- a/kern/CMakeLists.txt +++ b/kern/CMakeLists.txt @@ -10,7 +10,7 @@ target_include_directories("kern" PUBLIC ) target_link_libraries("kern" PUBLIC - "arch::all" + "arch::any" "gcc" ) diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 06083f3..a29fac8 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -1,10 +1,3 @@ -cmake_minimum_required(VERSION "3.27") - -project("kstd" - LANGUAGES CXX - VERSION "1.0.0" -) - add_library("kstd" STATIC) add_library("libs::kstd" ALIAS "kstd") diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index 386a127..7b9e58a 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -1,10 +1,3 @@ -cmake_minimum_required(VERSION "3.27") - -project("multiboot2" - LANGUAGES CXX - VERSION "1.0.0" -) - add_library("multiboot2" INTERFACE) add_library("libs::multiboot2" ALIAS "multiboot2") -- cgit v1.2.3 From d1aaaeb615e148a13f46223c84819ba828e5209f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:42:26 +0000 Subject: arch: make linkable --- CMakeLists.txt | 3 +- arch/CMakeLists.txt | 4 +++ arch/x86_64/CMakeLists.txt | 3 +- include/memory/asm_pointer.hpp | 76 --------------------------------------- kern/CMakeLists.txt | 7 ++-- kern/include/kern/asm_pointer.hpp | 76 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 83 deletions(-) delete mode 100644 include/memory/asm_pointer.hpp create mode 100644 kern/include/kern/asm_pointer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c08753b..a00b043 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,9 +32,8 @@ add_subdirectory("kern") add_subdirectory("arch") target_link_libraries("kernel" PRIVATE - "kern" - "arch::any" "arch::${CMAKE_SYSTEM_PROCESSOR}" + "os::kern" ) # #[============================================================================[ diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt index c7b2c15..eded57e 100644 --- a/arch/CMakeLists.txt +++ b/arch/CMakeLists.txt @@ -14,4 +14,8 @@ target_include_directories("arch-any" INTERFACE "include" ) +target_link_libraries("arch-any" INTERFACE + "libs::kstd" +) + add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 19bc78c..dd54b39 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -6,8 +6,7 @@ target_include_directories("arch-x86_64" PUBLIC ) target_link_libraries("arch-x86_64" PUBLIC - "kern" - + "arch::any" "libs::multiboot2" ) 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 - 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 - struct asm_pointer - { - /** @copydoc asm_pointer::asm_pointer */ - constexpr asm_pointer(Type const & pointer) - : m_pointer{&pointer} - { - } - - /** @copydoc asm_pointer::operator*() */ - auto constexpr operator*() -> Type const & { return *m_pointer; } - /** @copydoc asm_pointer::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/kern/CMakeLists.txt b/kern/CMakeLists.txt index 9bfe9e8..52c2cb5 100644 --- a/kern/CMakeLists.txt +++ b/kern/CMakeLists.txt @@ -1,4 +1,7 @@ -add_library("kern" OBJECT +add_library("kern" OBJECT) +add_library("os::kern" ALIAS "kern") + +target_sources("kern" PRIVATE "src/abort.cpp" "src/error.cpp" "src/main.cpp" @@ -11,6 +14,4 @@ target_include_directories("kern" PUBLIC target_link_libraries("kern" PUBLIC "arch::any" - - "gcc" ) diff --git a/kern/include/kern/asm_pointer.hpp b/kern/include/kern/asm_pointer.hpp new file mode 100644 index 0000000..4c25658 --- /dev/null +++ b/kern/include/kern/asm_pointer.hpp @@ -0,0 +1,76 @@ +#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 + 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 + struct asm_pointer + { + /** @copydoc asm_pointer::asm_pointer */ + constexpr asm_pointer(Type const & pointer) + : m_pointer{&pointer} + { + } + + /** @copydoc asm_pointer::operator*() */ + auto constexpr operator*() -> Type const & { return *m_pointer; } + /** @copydoc asm_pointer::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 -- cgit v1.2.3 From 763f38fff9336e40fce27565861e85c95d003a12 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:14:38 +0000 Subject: libs: move vector to kstd --- arch/x86_64/include/arch/stl/vector.hpp | 601 -------------------------------- kern/CMakeLists.txt | 1 + kern/src/kstd.cpp | 10 + libs/kstd/include/kstd/bits/os.hpp | 13 + libs/kstd/include/kstd/vector.hpp | 596 +++++++++++++++++++++++++++++++ 5 files changed, 620 insertions(+), 601 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/vector.hpp create mode 100644 kern/src/kstd.cpp create mode 100644 libs/kstd/include/kstd/bits/os.hpp create mode 100644 libs/kstd/include/kstd/vector.hpp diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp deleted file mode 100644 index 5314029..0000000 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ /dev/null @@ -1,601 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_STL_VECTOR_HPP -#define TEACHOS_ARCH_X86_64_STL_VECTOR_HPP - -#include "arch/exception_handling/panic.hpp" -#include "arch/stl/container.hpp" -#include "arch/stl/contiguous_pointer_iterator.hpp" - -#include - -namespace teachos::arch::stl -{ - /** - * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the vector instance should contain. - */ - template - struct vector - { - using value_type = T; ///< Type of the elements contained in the container. - using size_type = std::size_t; ///< Type of the size in the container. - using reference = value_type &; ///< Type of reference to the elements. - using const_reference = value_type const &; ///< Type of constant reference to the elements. - using pointer = value_type *; ///< Type of pointer to the elements. - using const_pointer = value_type const *; ///< Type of constant pointer to the elements. - - /** - * @brief Default Constructor. - */ - vector() = default; - - /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value. - * - * @param n Amount of elements we want to create and set the given value for. - * @param initial Inital value of all elements in the underlying data array. - */ - explicit vector(size_type n, value_type initial = value_type{}) - : _size(n) - , _capacity(n) - , _data(new value_type[_capacity]{}) - { - std::ranges::fill(*this, initial); - } - - /** - * @brief Constructs data by copying all element from the given exclusive range. - * - * @tparam InputIterator Template that should have atleast input iterator characteristics. - * @param first Input iterator to the first element in the range we want to copy from. - * @param last Input iterator to one past the last element in the range we want to copy from. - */ - template - explicit vector(InputIterator first, InputIterator last) - : _size(std::distance(first, last)) - , _capacity(std::distance(first, last)) - , _data(new value_type[_capacity]{}) - { - stl::container container{first, last}; - std::ranges::copy(container, _data); - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - explicit vector(std::initializer_list initalizer_list) - : _size(initalizer_list.size()) - , _capacity(initalizer_list.size()) - , _data(new value_type[_capacity]{}) - { - std::ranges::copy(initalizer_list, _data); - } - - /** - * @brief Copy constructor. - * - * @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. - */ - vector(vector const & other) - : _size(other._size) - , _capacity(other._capacity) - { - delete[] _data; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - } - - /** - * @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")]] - vector & operator=(vector const & other) - { - delete[] _data; - _size = other._size; - _capacity = other._capacity; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - return *this; - } - - /** - * @brief Destructor. - */ - ~vector() { delete[] _data; } - - /** - * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - [[gnu::section(".stl_text")]] - auto size() const -> size_type - { - return _size; - } - - /** - * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we - * exactly require to decrease the amount of allocations and deallocation to improve speed. - * - * @return Current amount of space the vector has for elements. - */ - [[gnu::section(".stl_text")]] - auto capacity() const -> size_type - { - return _capacity; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Does not do any bounds checks use at() for that. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto operator[](size_type index) -> reference - { - return _data[index]; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Does not do any bounds checks use at() for that. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto operator[](size_type index) const -> const_reference - { - return _data[index]; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto at(size_type index) -> reference - { - throw_if_out_of_range(index); - return this->operator[](index); - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto at(size_type index) const -> const_reference - { - throw_if_out_of_range(index); - return this->operator[](index); - } - - /** - * @brief Appends the given element value to the end of the container. The element is assigned through the - * assignment operator of the template type. The value is forwarded to the constructor as - * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). - * - * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, - * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. - * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @param value The value of the element to append. - */ - template - [[gnu::section(".stl_text")]] - auto push_back(U && value) -> void - { - increase_capacity_if_full(); - _data[_size] = std::forward(value); - (void)_size++; - } - - /** - * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the - * template type. The arguments args... are forwarded to the constructor as std::forward(args).... - * - * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case - * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only - * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - [[gnu::section(".stl_text")]] - auto emplace_back(Args &&... args) -> value_type & - { - increase_capacity_if_full(); - _data[_size] = value_type{std::forward(args)...}; - auto const index = _size++; - return _data[index]; - } - - /** - * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the - * further execution. Iterators and references to the last element are invalidated. The end() - * iterator is also invalidated. - */ - [[gnu::section(".stl_text")]] - auto pop_back() -> void - { - throw_if_empty(); - (void)_size--; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto begin() noexcept -> pointer - { - return _data; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto begin() const noexcept -> const_pointer - { - return _data; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto cbegin() const noexcept -> const_pointer - { - return begin(); - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto rbegin() noexcept -> pointer - { - return _data + _size - 1; - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto rbegin() const noexcept -> const_pointer - { - return _data + _size - 1; - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto crbegin() const noexcept -> const_pointer - { - return rbegin(); - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto end() noexcept -> pointer - { - return _data + _size; - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto end() const noexcept -> const_pointer - { - return _data + _size; - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto cend() const noexcept -> const_pointer - { - return end(); - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto rend() noexcept -> pointer - { - return _data + size - 1; - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto rend() const noexcept -> const_pointer - { - return _data + size - 1; - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto crend() const noexcept -> const_pointer - { - return rbegin(); - } - - /** - * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range - * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable - * in that case). - * - * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal - * to the address of the first element. - */ - [[gnu::section(".stl_text")]] - auto data() -> pointer - { - return _data; - } - - /** - * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range - * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable - * in that case). - * - * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal - * to the address of the first element. - */ - [[gnu::section(".stl_text")]] - auto data() const -> const_pointer - { - return _data; - } - - /** - * @brief Returns a reference to the first element in the container. Calling front on an empty container causes - * undefined behavior. - * - * @return Reference to the first element. - */ - [[gnu::section(".stl_text")]] - auto front() -> reference - { - throw_if_empty(); - return *begin(); - } - - /** - * @brief Returns a reference to the first element in the container. Calling front on an empty container causes - * undefined behavior. - * - * @return Reference to the first element. - */ - [[gnu::section(".stl_text")]] - auto front() const -> const_reference - { - throw_if_empty(); - return *begin(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto back() -> reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto back() const -> const_reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without - * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current - * capacity(), new storage is allocated, otherwise the function does nothing. - * - * reserve() does not change the size of the vector. - * - * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the - * elements are invalidated. Otherwise, no iterators or references are invalidated. - * - * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of - * the vector greater than the value of capacity(). - * - * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for - * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing - * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and - * decreased performance. For example, a function that receives an arbitrary vector by reference and appends - * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage - * characteristics. - * - * When inserting a range, the range version of insert() is generally preferable as it preserves the correct - * capacity growth behavior, unlike reserve() followed by a series of push_back()s. - * - * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. - * - * @param new_capacity New capacity of the vector, in number of elements - */ - [[gnu::section(".stl_text")]] - auto reserve(size_type new_capacity) -> void - { - if (new_capacity <= _capacity) - { - return; - } - - _capacity = new_capacity; - value_type * temp = new value_type[_capacity]{}; - stl::container container{begin(), end()}; - std::ranges::copy(container, temp); - delete[] _data; - _data = temp; - } - - /** - * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). - * - * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are - * invalidated. If no reallocation occurs, no iterators or references are invalidated. - */ - [[gnu::section(".stl_text")]] - auto shrink_to_fit() -> void - { - if (_size == _capacity) - { - return; - } - - _capacity = _size; - value_type * temp = new value_type[_capacity]{}; - stl::container container{begin(), end()}; - std::copy(container, temp); - delete[] _data; - _data = temp; - } - - /** - * @brief Wheter there are currently any items this container or not. - * - * @return True if there are no elements, false if there are. - */ - [[gnu::section(".stl_text")]] - auto empty() const -> bool - { - return _size <= 0; - } - - private: - /** - * @brief Halts the execution of the application if the data container is currently empty. - */ - auto throw_if_empty() const -> void - { - if (empty()) - { - exception_handling::panic("[Vector] Attempted to access element of currently empty vector"); - } - } - - auto throw_if_out_of_range(size_type index) const -> void - { - if (index >= _size) - { - exception_handling::panic("[Vector] Attempted to read element at invalid index"); - } - } - - /** - * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential - * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is - * normally perferable for the cache. - */ - auto increase_capacity_if_full() -> void - { - if (_size == _capacity) - { - reserve(_capacity == 0U ? 1U : _capacity * 2U); - } - } - - size_type _size = {}; ///< Amount of elements in the underlying data container - size_type _capacity = {}; ///< Amount of space for elements in the underlying data container - value_type * _data = {}; ///< Pointer to the first element in the underlying data container - }; - -} // namespace teachos::arch::stl - -#endif // TEACHOS_ARCH_X86_64_STL_VECTOR_HPP diff --git a/kern/CMakeLists.txt b/kern/CMakeLists.txt index 52c2cb5..677fdc2 100644 --- a/kern/CMakeLists.txt +++ b/kern/CMakeLists.txt @@ -4,6 +4,7 @@ add_library("os::kern" ALIAS "kern") target_sources("kern" PRIVATE "src/abort.cpp" "src/error.cpp" + "src/kstd.cpp" "src/main.cpp" "src/print.cpp" ) diff --git a/kern/src/kstd.cpp b/kern/src/kstd.cpp new file mode 100644 index 0000000..1b7050b --- /dev/null +++ b/kern/src/kstd.cpp @@ -0,0 +1,10 @@ +#include "kern/error.hpp" + +#include + +namespace kstd::os +{ + + auto panic(std::string_view message, std::source_location location) -> void { teachos::panic(message, location); } + +} // namespace kstd::os \ 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..0425b88 --- /dev/null +++ b/libs/kstd/include/kstd/bits/os.hpp @@ -0,0 +1,13 @@ +#ifndef KSTD_OS_HPP +#define KSTD_OS_HPP + +#include +#include + +namespace kstd::os +{ + [[noreturn]] + auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; +} + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/vector.hpp b/libs/kstd/include/kstd/vector.hpp new file mode 100644 index 0000000..1009e81 --- /dev/null +++ b/libs/kstd/include/kstd/vector.hpp @@ -0,0 +1,596 @@ +#ifndef KSTD_VECTOR_HPP +#define KSTD_VECTOR_HPP + +#include "bits/os.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the vector instance should contain. + */ + template + struct vector + { + using value_type = T; ///< Type of the elements contained in the container. + using size_type = std::size_t; ///< Type of the size in the container. + using reference = value_type &; ///< Type of reference to the elements. + using const_reference = value_type const &; ///< Type of constant reference to the elements. + using pointer = value_type *; ///< Type of pointer to the elements. + using const_pointer = value_type const *; ///< Type of constant pointer to the elements. + + /** + * @brief Default Constructor. + */ + vector() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + explicit vector(size_type n, value_type initial = value_type{}) + : _size(n) + , _capacity(n) + , _data(new value_type[_capacity]{}) + { + std::ranges::fill(*this, initial); + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + explicit vector(InputIterator first, InputIterator last) + : _size(std::distance(first, last)) + , _capacity(std::distance(first, last)) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(first, last, _data); + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + explicit vector(std::initializer_list initalizer_list) + : _size(initalizer_list.size()) + , _capacity(initalizer_list.size()) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(initalizer_list, _data); + } + + /** + * @brief Copy constructor. + * + * @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. + */ + vector(vector const & other) + : _size(other._size) + , _capacity(other._capacity) + { + delete[] _data; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + } + + /** + * @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")]] + vector & operator=(vector const & other) + { + delete[] _data; + _size = other._size; + _capacity = other._capacity; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + return *this; + } + + /** + * @brief Destructor. + */ + ~vector() { delete[] _data; } + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _size; + } + + /** + * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we + * exactly require to decrease the amount of allocations and deallocation to improve speed. + * + * @return Current amount of space the vector has for elements. + */ + [[gnu::section(".stl_text")]] + auto capacity() const -> size_type + { + return _capacity; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) -> reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) const -> const_reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) -> reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) const -> const_reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push_back(U && value) -> void + { + increase_capacity_if_full(); + _data[_size] = std::forward(value); + (void)_size++; + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace_back(Args &&... args) -> value_type & + { + increase_capacity_if_full(); + _data[_size] = value_type{std::forward(args)...}; + auto const index = _size++; + return _data[index]; + } + + /** + * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop_back() -> void + { + throw_if_empty(); + (void)_size--; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() noexcept -> pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() const noexcept -> const_pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto cbegin() const noexcept -> const_pointer + { + return begin(); + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() noexcept -> pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() const noexcept -> const_pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto crbegin() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() noexcept -> pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() const noexcept -> const_pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto cend() const noexcept -> const_pointer + { + return end(); + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() noexcept -> pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() const noexcept -> const_pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto crend() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() -> pointer + { + return _data; + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() const -> const_pointer + { + return _data; + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() -> reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() const -> const_reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() -> reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() const -> const_reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without + * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current + * capacity(), new storage is allocated, otherwise the function does nothing. + * + * reserve() does not change the size of the vector. + * + * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the + * elements are invalidated. Otherwise, no iterators or references are invalidated. + * + * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of + * the vector greater than the value of capacity(). + * + * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for + * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing + * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and + * decreased performance. For example, a function that receives an arbitrary vector by reference and appends + * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage + * characteristics. + * + * When inserting a range, the range version of insert() is generally preferable as it preserves the correct + * capacity growth behavior, unlike reserve() followed by a series of push_back()s. + * + * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. + * + * @param new_capacity New capacity of the vector, in number of elements + */ + [[gnu::section(".stl_text")]] + auto reserve(size_type new_capacity) -> void + { + if (new_capacity <= _capacity) + { + return; + } + + _capacity = new_capacity; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). + * + * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are + * invalidated. If no reallocation occurs, no iterators or references are invalidated. + */ + [[gnu::section(".stl_text")]] + auto shrink_to_fit() -> void + { + if (_size == _capacity) + { + return; + } + + _capacity = _size; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _size <= 0; + } + + private: + /** + * @brief Halts the execution of the application if the data container is currently empty. + */ + auto throw_if_empty() const -> void + { + if (empty()) + { + os::panic("[Vector] Attempted to access element of currently empty vector"); + } + } + + auto throw_if_out_of_range(size_type index) const -> void + { + if (index >= _size) + { + os::panic("[Vector] Attempted to read element at invalid index"); + } + } + + /** + * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential + * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is + * normally perferable for the cache. + */ + auto increase_capacity_if_full() -> void + { + if (_size == _capacity) + { + reserve(_capacity == 0U ? 1U : _capacity * 2U); + } + } + + size_type _size = {}; ///< Amount of elements in the underlying data container + size_type _capacity = {}; ///< Amount of space for elements in the underlying data container + value_type * _data = {}; ///< Pointer to the first element in the underlying data container + }; + +} // namespace kstd + +#endif -- cgit v1.2.3 From 576935b6448802138639a324535614e0a966ead1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:16:19 +0000 Subject: libs: move unique_ptr to kstd --- arch/x86_64/include/arch/stl/unique_pointer.hpp | 204 ----------------------- libs/kstd/include/kstd/unique_pointer.hpp | 206 ++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 204 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/unique_pointer.hpp create mode 100644 libs/kstd/include/kstd/unique_pointer.hpp diff --git a/arch/x86_64/include/arch/stl/unique_pointer.hpp b/arch/x86_64/include/arch/stl/unique_pointer.hpp deleted file mode 100644 index 03b4ef3..0000000 --- a/arch/x86_64/include/arch/stl/unique_pointer.hpp +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_STL_UNIQUE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_STL_UNIQUE_POINTER_HPP - -namespace teachos::arch::stl -{ - /** - * @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. - * - * @tparam T Type of the managed object. - */ - template - struct unique_pointer - { - /** - * @brief Constructor. - * - * @param ptr A pointer to an object to manage (default is nullptr). - */ - [[gnu::section(".stl_text")]] - explicit unique_pointer(T * ptr = nullptr) - : pointer(ptr) - { - // Nothing to do. - } - - /** - * @brief Destructor that deletes the managed object. - */ - [[gnu::section(".stl_text")]] - ~unique_pointer() - { - delete pointer; - } - - /** - * @brief Deleted copy constructor to enforce unique ownership. - */ - unique_pointer(const unique_pointer &) = delete; - - /** - * @brief Deleted copy assignment operator to enforce unique ownership. - */ - auto operator=(const unique_pointer &) -> unique_pointer & = delete; - - /** - * @brief Move constructor. - * - * @param other Unique pointer to move from. - */ - [[gnu::section(".stl_text")]] - unique_pointer(unique_pointer && other) noexcept - : pointer(other.pointer) - { - other.pointer = nullptr; - } - - /** - * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). - * - * @param other Smart pointer from which ownership will be transferred. - * @return Reference to this unique pointer. - */ - [[gnu::section(".stl_text")]] - auto operator=(unique_pointer && other) noexcept -> unique_pointer & - { - if (this != &other) - { - delete pointer; - pointer = other.pointer; - other.pointer = nullptr; - } - return *this; - } - - /** - * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. - * - * @return Returns the object owned by *this, equivalent to *get(). - */ - [[gnu::section(".stl_text")]] - auto operator*() const -> T & - { - return *pointer; - } - - /** - * @brief Member access operator. - * - * @return Returns a pointer to the object owned by *this, i.e. get(). - */ - [[gnu::section(".stl_text")]] - auto operator->() const -> T * - { - return pointer; - } - - /** - * @brief Returns a pointer to the managed object or nullptr if no object is owned. - * - * @return Pointer to the managed object or nullptr if no object is owned. - */ - [[gnu::section(".stl_text")]] - auto get() const -> T * - { - return pointer; - } - - /** - * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. - * - * @return true if *this owns an object, false otherwise. - */ - [[gnu::section(".stl_text")]] - explicit operator bool() const noexcept - { - return pointer != nullptr; - } - - /** - * @brief Releases the ownership of the managed object, if any. - * get() returns nullptr after the call. - * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). - * - * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be - * returned by get() before the call. - */ - [[gnu::section(".stl_text")]] - auto release() -> T * - { - T * temp = pointer; - pointer = nullptr; - return temp; - } - - /** - * @brief Replaces the managed object. - * - * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, - * except where provided as a compiler extension or as a debugging assert. Note that code such as - * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. - * - * @param ptr Pointer to a new object to manage (default = nullptr). - */ - [[gnu::section(".stl_text")]] - auto reset(T * ptr = nullptr) -> void - { - delete pointer; - pointer = ptr; - } - - /** - * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. - * - * @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 - { - using std::swap; - swap(pointer, other.pointer); - } - - /** - * @brief Defaulted three-way comparator operator. - */ - [[gnu::section(".stl_text")]] - auto operator<=>(const unique_pointer & other) const = default; - - private: - T * pointer; ///< The managed pointer. - }; - - /** - * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls - * lhs.swap(rhs). - * - * @tparam T Type of the managed object. - * @param lhs, rhs Smart pointers whose contents to swap. - */ - template - auto swap(unique_pointer & lhs, unique_pointer & 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 - * 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(new T(std::forward(args)...)). - * - * @tparam T Type of the managed object. - * @tparam Args Argument types for T's constructor. - * @param args List of arguments with which an instance of T will be constructed. - * @returns Unique_pointer of an instance of type T. - */ - template - auto make_unique(Args &&... args) -> unique_pointer - { - return unique_pointer(new T(std::forward(args)...)); - } -} // namespace teachos::arch::stl - -#endif // TEACHOS_ARCH_X86_64_STL_UNIQUE_POINTER_HPP \ No newline at end of file diff --git a/libs/kstd/include/kstd/unique_pointer.hpp b/libs/kstd/include/kstd/unique_pointer.hpp new file mode 100644 index 0000000..2861646 --- /dev/null +++ b/libs/kstd/include/kstd/unique_pointer.hpp @@ -0,0 +1,206 @@ +#ifndef KSTD_UNIQUE_POINTER_HPP +#define KSTD_UNIQUE_POINTER_HPP + +#include + +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. + * + * @tparam T Type of the managed object. + */ + template + struct unique_pointer + { + /** + * @brief Constructor. + * + * @param ptr A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit unique_pointer(T * ptr = nullptr) + : pointer(ptr) + { + // Nothing to do. + } + + /** + * @brief Destructor that deletes the managed object. + */ + [[gnu::section(".stl_text")]] + ~unique_pointer() + { + delete pointer; + } + + /** + * @brief Deleted copy constructor to enforce unique ownership. + */ + unique_pointer(const unique_pointer &) = delete; + + /** + * @brief Deleted copy assignment operator to enforce unique ownership. + */ + auto operator=(const unique_pointer &) -> unique_pointer & = delete; + + /** + * @brief Move constructor. + * + * @param other Unique pointer to move from. + */ + [[gnu::section(".stl_text")]] + unique_pointer(unique_pointer && other) noexcept + : pointer(other.pointer) + { + other.pointer = nullptr; + } + + /** + * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). + * + * @param other Smart pointer from which ownership will be transferred. + * @return Reference to this unique pointer. + */ + [[gnu::section(".stl_text")]] + auto operator=(unique_pointer && other) noexcept -> unique_pointer & + { + if (this != &other) + { + delete pointer; + pointer = other.pointer; + other.pointer = nullptr; + } + return *this; + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const noexcept + { + return pointer != nullptr; + } + + /** + * @brief Releases the ownership of the managed object, if any. + * get() returns nullptr after the call. + * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). + * + * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be + * returned by get() before the call. + */ + [[gnu::section(".stl_text")]] + auto release() -> T * + { + T * temp = pointer; + pointer = nullptr; + return temp; + } + + /** + * @brief Replaces the managed object. + * + * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, + * except where provided as a compiler extension or as a debugging assert. Note that code such as + * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + auto reset(T * ptr = nullptr) -> void + { + delete pointer; + pointer = ptr; + } + + /** + * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. + * + * @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 + { + using std::swap; + swap(pointer, other.pointer); + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const unique_pointer & other) const = default; + + private: + T * pointer; ///< The managed pointer. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(unique_pointer & lhs, unique_pointer & 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 + * 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(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Unique_pointer of an instance of type T. + */ + template + auto make_unique(Args &&... args) -> unique_pointer + { + return unique_pointer(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file -- cgit v1.2.3 From f12fa671ccadfdeaca1529157c3bd458f9e37c30 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:18:45 +0000 Subject: libs: move shared_pointer to kstd --- arch/x86_64/include/arch/stl/shared_pointer.hpp | 269 ------------------------ libs/kstd/include/kstd/shared_pointer.hpp | 269 ++++++++++++++++++++++++ 2 files changed, 269 insertions(+), 269 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/shared_pointer.hpp create mode 100644 libs/kstd/include/kstd/shared_pointer.hpp diff --git a/arch/x86_64/include/arch/stl/shared_pointer.hpp b/arch/x86_64/include/arch/stl/shared_pointer.hpp deleted file mode 100644 index c9796a8..0000000 --- a/arch/x86_64/include/arch/stl/shared_pointer.hpp +++ /dev/null @@ -1,269 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP -#define TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP - -#include - -namespace teachos::arch::stl -{ - /** - * @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 - * 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. - * - * @tparam T The type of the managed object. - */ - template - struct shared_pointer - { - /** - * @brief Constructor. - * - * @param pointer A pointer to an object to manage (default is nullptr). - */ - [[gnu::section(".stl_text")]] - explicit shared_pointer(T * pointer = nullptr) - : pointer(pointer) - , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) - { - // Nothing to do. - } - - /** - * @brief Copy constructor. - * - * @param other The shared_pointer to copy from. - */ - [[gnu::section(".stl_text")]] - shared_pointer(const shared_pointer & other) - : pointer(other.pointer) - , ref_count(other.ref_count) - { - if (pointer != nullptr) - { - ++(*ref_count); - } - } - - /** - * @brief Move constructor. - * - * @param other The shared_pointer to move from. - */ - [[gnu::section(".stl_text")]] - shared_pointer(shared_pointer && other) noexcept - : pointer(other.pointer) - , ref_count(other.ref_count) - { - other.pointer = nullptr; - other.ref_count = nullptr; - } - - /** - * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the - * object managed by r. If r manages no object, *this manages no object too. Equivalent to - * shared_ptr(r).swap(*this). - * - * @param other Another smart pointer to share the ownership with. - * @return Reference to this shared pointer. - */ - [[gnu::section(".stl_text")]] - shared_pointer & operator=(const shared_pointer & other) - { - if (this != &other) - { - cleanup(); - pointer = other.pointer; - ref_count = other.ref_count; - - if (pointer != nullptr) - { - ++(*ref_count); - } - } - - return *this; - } - - /** - * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of - * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). - * - * @param other Another smart pointer to acquire the ownership from. - * @return Reference to this shared pointer. - */ - [[gnu::section(".stl_text")]] - shared_pointer & operator=(shared_pointer && other) noexcept - { - if (this != &other) - { - cleanup(); - pointer = other.pointer; - ref_count = other.ref_count; - other.pointer = nullptr; - other.ref_count = nullptr; - } - - return *this; - } - - /** - * @brief Destructor. Cleans up resources if necessary. - */ - [[gnu::section(".stl_text")]] - ~shared_pointer() - { - cleanup(); - } - - /** - * @brief Replaces the managed object. - * - * @param ptr Pointer to a new object to manage (default = nullptr). - */ - [[gnu::section(".stl_text")]] - void reset(T * ptr = nullptr) - { - cleanup(); - pointer = ptr; - ref_count = new std::atomic(ptr != nullptr ? 1 : 0); - } - - /** - * @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. - */ - [[gnu::section(".stl_text")]] - void swap(shared_pointer & other) - { - std::swap(pointer, other.pointer); - std::swap(ref_count, other.ref_count); - } - - /** - * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. - * - * @return Returns the object owned by *this, equivalent to *get(). - */ - [[gnu::section(".stl_text")]] - auto operator*() const -> T & - { - return *pointer; - } - - /** - * @brief Member access operator. - * - * @return Returns a pointer to the object owned by *this, i.e. get(). - */ - [[gnu::section(".stl_text")]] - auto operator->() const -> T * - { - return pointer; - } - - /** - * @brief Returns a pointer to the managed object or nullptr if no object is owned. - * - * @return Pointer to the managed object or nullptr if no object is owned. - */ - [[gnu::section(".stl_text")]] - auto get() const -> T * - { - return pointer; - } - - /** - * @brief Returns the number of different shared_pointer 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 - * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, - * there are no other owners. - * - * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed - * object. - */ - [[gnu::section(".stl_text")]] - auto use_count() const -> std::size_t - { - if (pointer != nullptr) - { - return *ref_count; - } - - return 0; - } - - /** - * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. - * - * @return true if *this owns an object, false otherwise. - */ - [[gnu::section(".stl_text")]] - explicit operator bool() const - { - return pointer != nullptr; - } - - /** - * @brief Defaulted three-way comparator operator. - */ - [[gnu::section(".stl_text")]] - auto operator<=>(const shared_pointer & other) const = default; - - private: - /** - * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. - */ - [[gnu::section(".stl_text")]] - auto cleanup() -> void - { - if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) - { - delete pointer; - delete ref_count; - } - } - - T * pointer; ///< The managed object. - std::atomic * ref_count; ///< Reference count. - }; - - /** - * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls - * lhs.swap(rhs). - * - * @tparam T Type of the managed object. - * @param lhs, rhs Smart pointers whose contents to swap. - */ - template - auto swap(shared_pointer & lhs, shared_pointer & 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 - * 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(new T(std::forward(args)...)). - * - * @tparam T Type of the managed object. - * @tparam Args Argument types for T's constructor. - * @param args List of arguments with which an instance of T will be constructed. - * @returns Shared_pointer of an instance of type T. - */ - template - auto make_shared(Args &&... args) -> shared_pointer - { - return shared_pointer(new T(std::forward(args)...)); - } -} // namespace teachos::arch::stl - -#endif // TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP \ No newline at end of file diff --git a/libs/kstd/include/kstd/shared_pointer.hpp b/libs/kstd/include/kstd/shared_pointer.hpp new file mode 100644 index 0000000..4717117 --- /dev/null +++ b/libs/kstd/include/kstd/shared_pointer.hpp @@ -0,0 +1,269 @@ +#ifndef KSTD_SHARED_POINTER_HPP +#define KSTD_SHARED_POINTER_HPP + +#include + +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 + * 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. + * + * @tparam T The type of the managed object. + */ + template + struct shared_pointer + { + /** + * @brief Constructor. + * + * @param pointer A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit shared_pointer(T * pointer = nullptr) + : pointer(pointer) + , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @param other The shared_pointer to copy from. + */ + [[gnu::section(".stl_text")]] + shared_pointer(const shared_pointer & other) + : pointer(other.pointer) + , ref_count(other.ref_count) + { + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + /** + * @brief Move constructor. + * + * @param other The shared_pointer to move from. + */ + [[gnu::section(".stl_text")]] + shared_pointer(shared_pointer && other) noexcept + : pointer(other.pointer) + , ref_count(other.ref_count) + { + other.pointer = nullptr; + other.ref_count = nullptr; + } + + /** + * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the + * object managed by r. If r manages no object, *this manages no object too. Equivalent to + * shared_ptr(r).swap(*this). + * + * @param other Another smart pointer to share the ownership with. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_pointer & operator=(const shared_pointer & other) + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + return *this; + } + + /** + * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of + * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). + * + * @param other Another smart pointer to acquire the ownership from. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_pointer & operator=(shared_pointer && other) noexcept + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + other.pointer = nullptr; + other.ref_count = nullptr; + } + + return *this; + } + + /** + * @brief Destructor. Cleans up resources if necessary. + */ + [[gnu::section(".stl_text")]] + ~shared_pointer() + { + cleanup(); + } + + /** + * @brief Replaces the managed object. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + void reset(T * ptr = nullptr) + { + cleanup(); + pointer = ptr; + ref_count = new std::atomic(ptr != nullptr ? 1 : 0); + } + + /** + * @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. + */ + [[gnu::section(".stl_text")]] + void swap(shared_pointer & other) + { + std::swap(pointer, other.pointer); + std::swap(ref_count, other.ref_count); + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Returns the number of different shared_pointer 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 + * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, + * there are no other owners. + * + * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed + * object. + */ + [[gnu::section(".stl_text")]] + auto use_count() const -> std::size_t + { + if (pointer != nullptr) + { + return *ref_count; + } + + return 0; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const + { + return pointer != nullptr; + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const shared_pointer & other) const = default; + + private: + /** + * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. + */ + [[gnu::section(".stl_text")]] + auto cleanup() -> void + { + if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) + { + delete pointer; + delete ref_count; + } + } + + T * pointer; ///< The managed object. + std::atomic * ref_count; ///< Reference count. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(shared_pointer & lhs, shared_pointer & 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 + * 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(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Shared_pointer of an instance of type T. + */ + template + auto make_shared(Args &&... args) -> shared_pointer + { + return shared_pointer(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file -- cgit v1.2.3 From 67785bfc07072fce56331052c1cd8de023eb2f4c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:19:00 +0000 Subject: x86_64: remove container --- arch/x86_64/include/arch/stl/container.hpp | 99 ---------- .../arch/stl/contiguous_pointer_iterator.hpp | 216 --------------------- 2 files changed, 315 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/container.hpp delete mode 100644 arch/x86_64/include/arch/stl/contiguous_pointer_iterator.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 - -namespace teachos::arch::stl -{ - /** - * @brief Minimal iterator concept required for usage in container - */ - template - concept Iterator = std::forward_iterator; - - /** - * @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 - 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 - -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 - 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 -- cgit v1.2.3 From be0d5d9453edb871393cd8ee5c83ad15f6ef8c9d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:21:01 +0000 Subject: libs: move stack to kstd --- arch/x86_64/include/arch/stl/stack.hpp | 212 -------------------------------- libs/kstd/include/kstd/stack.hpp | 213 +++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 212 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/stack.hpp create mode 100644 libs/kstd/include/kstd/stack.hpp diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/arch/x86_64/include/arch/stl/stack.hpp deleted file mode 100644 index 48bcf10..0000000 --- a/arch/x86_64/include/arch/stl/stack.hpp +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_STL_STACK_HPP -#define TEACHOS_ARCH_X86_64_STL_STACK_HPP - -#include "arch/exception_handling/panic.hpp" -#include "arch/stl/vector.hpp" - -namespace teachos::arch::stl -{ - /** - * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the stack instance should contain. - * @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> - struct stack - { - using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. - using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. - using size_type = Container::size_type; ///< Type of the size in the underlying container. - using reference = Container::reference; ///< Type of reference to the elements. - using const_reference = Container::const_reference; ///< Type of constant reference to the elements. - - /** - * @brief Default Constructor. - */ - stack() = default; - - /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value. - * - * @param n Amount of elements we want to create and set the given value for. - * @param initial Inital value of all elements in the underlying data array. - */ - [[gnu::section(".stl_text")]] - explicit stack(size_type n, value_type initial = value_type{}) - : _container(n, initial) - { - // Nothing to do. - } - - /** - * @brief Constructs data by copying all element from the given exclusive range. - * - * @tparam InputIterator Template that should have atleast input iterator characteristics. - * @param first Input iterator to the first element in the range we want to copy from. - * @param last Input iterator to one past the last element in the range we want to copy from. - */ - template - [[gnu::section(".stl_text")]] - explicit stack(InputIterator first, InputIterator last) - : _container(first, last) - { - // Nothing to do. - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - [[gnu::section(".stl_text")]] - explicit stack(std::initializer_list initalizer_list) - : _container(initalizer_list) - { - // Nothing to do. - } - - /** - * @brief Copy constructor. - * - * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all - * elements from it. - * - * @param other Other instance of stack we want to copy the data from. - */ - [[gnu::section(".stl_text")]] - stack(stack const & other) - : _container(other) - { - // Nothing to do. - } - - /** - * @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 & operator=(stack const & other) - { - _container = other; - } - - /** - * @brief Destructor. - */ - ~stack() = default; - - /** - * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - [[gnu::section(".stl_text")]] - auto size() const -> size_type - { - return _container.size(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto top() -> reference - { - return _container.back(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto top() const -> const_reference - { - return _container.back(); - } - - /** - * @brief Appends the given element value to the end of the container. The element is assigned through the - * assignment operator of the template type. The value is forwarded to the constructor as - * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). - * - * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, - * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. - * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @param value The value of the element to append. - */ - template - [[gnu::section(".stl_text")]] - auto push(U && value) -> void - { - _container.push_back(std::forward(value)); - } - - /** - * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the - * template type. The arguments args... are forwarded to the constructor as std::forward(args).... - * - * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case - * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only - * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - [[gnu::section(".stl_text")]] - auto emplace(Args &&... args) -> reference - { - _container.emplace_back(std::forward(args)...); - } - - /** - * @brief Removes the last element of the container. - * - * @note Calling pop_back on an empty container results in halting the - * further execution. Iterators and references to the last element are invalidated. The end() - * iterator is also invalidated. - */ - [[gnu::section(".stl_text")]] - auto pop() -> void - { - _container.pop_back(); - } - - /** - * @brief Wheter there are currently any items this container or not. - * - * @return True if there are no elements, false if there are. - */ - [[gnu::section(".stl_text")]] - auto empty() const -> bool - { - return _container.empty(); - } - - private: - container_type _container = {}; ///< Underlying container used by the stack to actually save the data. - }; - -} // namespace teachos::arch::stl - -#endif // TEACHOS_ARCH_X86_64_STL_STACK_HPP diff --git a/libs/kstd/include/kstd/stack.hpp b/libs/kstd/include/kstd/stack.hpp new file mode 100644 index 0000000..8c702cf --- /dev/null +++ b/libs/kstd/include/kstd/stack.hpp @@ -0,0 +1,213 @@ +#ifndef KSTD_STACK_HPP +#define KSTD_STACK_HPP + +#include "kstd/vector.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the stack instance should contain. + * @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> + struct stack + { + using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. + using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. + using size_type = Container::size_type; ///< Type of the size in the underlying container. + using reference = Container::reference; ///< Type of reference to the elements. + using const_reference = Container::const_reference; ///< Type of constant reference to the elements. + + /** + * @brief Default Constructor. + */ + stack() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + [[gnu::section(".stl_text")]] + explicit stack(size_type n, value_type initial = value_type{}) + : _container(n, initial) + { + // Nothing to do. + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + [[gnu::section(".stl_text")]] + explicit stack(InputIterator first, InputIterator last) + : _container(first, last) + { + // Nothing to do. + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + [[gnu::section(".stl_text")]] + explicit stack(std::initializer_list initalizer_list) + : _container(initalizer_list) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all + * elements from it. + * + * @param other Other instance of stack we want to copy the data from. + */ + [[gnu::section(".stl_text")]] + stack(stack const & other) + : _container(other) + { + // Nothing to do. + } + + /** + * @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 & operator=(stack const & other) + { + _container = other; + } + + /** + * @brief Destructor. + */ + ~stack() = default; + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _container.size(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() -> reference + { + return _container.back(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() const -> const_reference + { + return _container.back(); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push(U && value) -> void + { + _container.push_back(std::forward(value)); + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace(Args &&... args) -> reference + { + _container.emplace_back(std::forward(args)...); + } + + /** + * @brief Removes the last element of the container. + * + * @note Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop() -> void + { + _container.pop_back(); + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _container.empty(); + } + + private: + container_type _container = {}; ///< Underlying container used by the stack to actually save the data. + }; + +} // namespace kstd + +#endif -- cgit v1.2.3 From 23b75cc23b8bab97eb2803e5110641c0f04bfc80 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:21:26 +0000 Subject: x86_64: remove forward_value_iterator --- .../include/arch/stl/forward_value_iterator.hpp | 121 --------------------- 1 file changed, 121 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/forward_value_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 - -namespace teachos::arch::stl -{ - /** - * @brief Concept for a type to have a post and prefix increment operator, that returns the correct type. - */ - template - concept Incrementable = requires(T t) { - { ++t } -> std::same_as; - { t++ } -> std::same_as; - }; - - /** - * @brief Iterable concept for the forward value iterator, meaning the type itself is incrementable and comparable. - */ - template - concept Iterable = std::regular && Incrementable; - - /** - * @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 - 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 -- cgit v1.2.3 From 4e99a7586748f9acd7027abc4c86a8df5f0c2e6f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:26:05 +0000 Subject: kstd: improve resemblence of STL --- libs/kstd/include/kstd/bits/shared_ptr.hpp | 269 +++++++++++++++++++++++++++++ libs/kstd/include/kstd/bits/unique_ptr.hpp | 206 ++++++++++++++++++++++ libs/kstd/include/kstd/memory.hpp | 7 + libs/kstd/include/kstd/shared_pointer.hpp | 269 ----------------------------- libs/kstd/include/kstd/unique_pointer.hpp | 206 ---------------------- 5 files changed, 482 insertions(+), 475 deletions(-) create mode 100644 libs/kstd/include/kstd/bits/shared_ptr.hpp create mode 100644 libs/kstd/include/kstd/bits/unique_ptr.hpp create mode 100644 libs/kstd/include/kstd/memory.hpp delete mode 100644 libs/kstd/include/kstd/shared_pointer.hpp delete mode 100644 libs/kstd/include/kstd/unique_pointer.hpp diff --git a/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp new file mode 100644 index 0000000..d41b165 --- /dev/null +++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp @@ -0,0 +1,269 @@ +#ifndef KSTD_BITS_SHARED_PTR_HPP +#define KSTD_BITS_SHARED_PTR_HPP + +#include + +namespace kstd +{ + /** + * @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several + * 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. + * + * @tparam T The type of the managed object. + */ + template + struct shared_ptr + { + /** + * @brief Constructor. + * + * @param pointer A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit shared_ptr(T * pointer = nullptr) + : pointer(pointer) + , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @param other The shared_ptr to copy from. + */ + [[gnu::section(".stl_text")]] + shared_ptr(const shared_ptr & other) + : pointer(other.pointer) + , ref_count(other.ref_count) + { + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + /** + * @brief Move constructor. + * + * @param other The shared_ptr to move from. + */ + [[gnu::section(".stl_text")]] + shared_ptr(shared_ptr && other) noexcept + : pointer(other.pointer) + , ref_count(other.ref_count) + { + other.pointer = nullptr; + other.ref_count = nullptr; + } + + /** + * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the + * object managed by r. If r manages no object, *this manages no object too. Equivalent to + * shared_ptr(r).swap(*this). + * + * @param other Another smart pointer to share the ownership with. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_ptr & operator=(const shared_ptr & other) + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + return *this; + } + + /** + * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of + * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). + * + * @param other Another smart pointer to acquire the ownership from. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_ptr & operator=(shared_ptr && other) noexcept + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + other.pointer = nullptr; + other.ref_count = nullptr; + } + + return *this; + } + + /** + * @brief Destructor. Cleans up resources if necessary. + */ + [[gnu::section(".stl_text")]] + ~shared_ptr() + { + cleanup(); + } + + /** + * @brief Replaces the managed object. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + void reset(T * ptr = nullptr) + { + cleanup(); + pointer = ptr; + ref_count = new std::atomic(ptr != nullptr ? 1 : 0); + } + + /** + * @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not + * adjusted. + * + * @param other The shared_ptr to swap with. + */ + [[gnu::section(".stl_text")]] + void swap(shared_ptr & other) + { + std::swap(pointer, other.pointer); + std::swap(ref_count, other.ref_count); + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @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 + * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, + * there are no other owners. + * + * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed + * object. + */ + [[gnu::section(".stl_text")]] + auto use_count() const -> std::size_t + { + if (pointer != nullptr) + { + return *ref_count; + } + + return 0; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const + { + return pointer != nullptr; + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const shared_ptr & other) const = default; + + private: + /** + * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. + */ + [[gnu::section(".stl_text")]] + auto cleanup() -> void + { + if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) + { + delete pointer; + delete ref_count; + } + } + + T * pointer; ///< The managed object. + std::atomic * ref_count; ///< Reference count. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(shared_ptr & lhs, shared_ptr & rhs) -> void + { + lhs.swap(rhs); + } + + /** + * @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_ptr(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Shared_pointer of an instance of type T. + */ + template + auto make_shared(Args &&... args) -> shared_ptr + { + return shared_ptr(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/unique_ptr.hpp b/libs/kstd/include/kstd/bits/unique_ptr.hpp new file mode 100644 index 0000000..1932913 --- /dev/null +++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp @@ -0,0 +1,206 @@ +#ifndef KSTD_BITS_UNIQUE_POINTER_HPP +#define KSTD_BITS_UNIQUE_POINTER_HPP + +#include + +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_ptr goes out of scope. + * + * @tparam T Type of the managed object. + */ + template + struct unique_ptr + { + /** + * @brief Constructor. + * + * @param ptr A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit unique_ptr(T * ptr = nullptr) + : pointer(ptr) + { + // Nothing to do. + } + + /** + * @brief Destructor that deletes the managed object. + */ + [[gnu::section(".stl_text")]] + ~unique_ptr() + { + delete pointer; + } + + /** + * @brief Deleted copy constructor to enforce unique ownership. + */ + unique_ptr(const unique_ptr &) = delete; + + /** + * @brief Deleted copy assignment operator to enforce unique ownership. + */ + auto operator=(const unique_ptr &) -> unique_ptr & = delete; + + /** + * @brief Move constructor. + * + * @param other Unique pointer to move from. + */ + [[gnu::section(".stl_text")]] + unique_ptr(unique_ptr && other) noexcept + : pointer(other.pointer) + { + other.pointer = nullptr; + } + + /** + * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). + * + * @param other Smart pointer from which ownership will be transferred. + * @return Reference to this unique pointer. + */ + [[gnu::section(".stl_text")]] + auto operator=(unique_ptr && other) noexcept -> unique_ptr & + { + if (this != &other) + { + delete pointer; + pointer = other.pointer; + other.pointer = nullptr; + } + return *this; + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const noexcept + { + return pointer != nullptr; + } + + /** + * @brief Releases the ownership of the managed object, if any. + * get() returns nullptr after the call. + * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). + * + * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be + * returned by get() before the call. + */ + [[gnu::section(".stl_text")]] + auto release() -> T * + { + T * temp = pointer; + pointer = nullptr; + return temp; + } + + /** + * @brief Replaces the managed object. + * + * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, + * except where provided as a compiler extension or as a debugging assert. Note that code such as + * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + auto reset(T * ptr = nullptr) -> void + { + delete pointer; + pointer = ptr; + } + + /** + * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. + * + * @param other Another unique_ptr object to swap the managed object and the deleter with. + */ + [[gnu::section(".stl_text")]] + auto swap(unique_ptr & other) -> void + { + using std::swap; + swap(pointer, other.pointer); + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const unique_ptr & other) const = default; + + private: + T * pointer; ///< The managed pointer. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(unique_ptr & lhs, unique_ptr & rhs) -> void + { + lhs.swap(rhs); + } + + /** + * @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_ptr(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Unique_pointer of an instance of type T. + */ + template + auto make_unique(Args &&... args) -> unique_ptr + { + return unique_ptr(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/memory.hpp b/libs/kstd/include/kstd/memory.hpp new file mode 100644 index 0000000..cab2fba --- /dev/null +++ b/libs/kstd/include/kstd/memory.hpp @@ -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/libs/kstd/include/kstd/shared_pointer.hpp b/libs/kstd/include/kstd/shared_pointer.hpp deleted file mode 100644 index 4717117..0000000 --- a/libs/kstd/include/kstd/shared_pointer.hpp +++ /dev/null @@ -1,269 +0,0 @@ -#ifndef KSTD_SHARED_POINTER_HPP -#define KSTD_SHARED_POINTER_HPP - -#include - -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 - * 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. - * - * @tparam T The type of the managed object. - */ - template - struct shared_pointer - { - /** - * @brief Constructor. - * - * @param pointer A pointer to an object to manage (default is nullptr). - */ - [[gnu::section(".stl_text")]] - explicit shared_pointer(T * pointer = nullptr) - : pointer(pointer) - , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) - { - // Nothing to do. - } - - /** - * @brief Copy constructor. - * - * @param other The shared_pointer to copy from. - */ - [[gnu::section(".stl_text")]] - shared_pointer(const shared_pointer & other) - : pointer(other.pointer) - , ref_count(other.ref_count) - { - if (pointer != nullptr) - { - ++(*ref_count); - } - } - - /** - * @brief Move constructor. - * - * @param other The shared_pointer to move from. - */ - [[gnu::section(".stl_text")]] - shared_pointer(shared_pointer && other) noexcept - : pointer(other.pointer) - , ref_count(other.ref_count) - { - other.pointer = nullptr; - other.ref_count = nullptr; - } - - /** - * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the - * object managed by r. If r manages no object, *this manages no object too. Equivalent to - * shared_ptr(r).swap(*this). - * - * @param other Another smart pointer to share the ownership with. - * @return Reference to this shared pointer. - */ - [[gnu::section(".stl_text")]] - shared_pointer & operator=(const shared_pointer & other) - { - if (this != &other) - { - cleanup(); - pointer = other.pointer; - ref_count = other.ref_count; - - if (pointer != nullptr) - { - ++(*ref_count); - } - } - - return *this; - } - - /** - * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of - * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). - * - * @param other Another smart pointer to acquire the ownership from. - * @return Reference to this shared pointer. - */ - [[gnu::section(".stl_text")]] - shared_pointer & operator=(shared_pointer && other) noexcept - { - if (this != &other) - { - cleanup(); - pointer = other.pointer; - ref_count = other.ref_count; - other.pointer = nullptr; - other.ref_count = nullptr; - } - - return *this; - } - - /** - * @brief Destructor. Cleans up resources if necessary. - */ - [[gnu::section(".stl_text")]] - ~shared_pointer() - { - cleanup(); - } - - /** - * @brief Replaces the managed object. - * - * @param ptr Pointer to a new object to manage (default = nullptr). - */ - [[gnu::section(".stl_text")]] - void reset(T * ptr = nullptr) - { - cleanup(); - pointer = ptr; - ref_count = new std::atomic(ptr != nullptr ? 1 : 0); - } - - /** - * @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. - */ - [[gnu::section(".stl_text")]] - void swap(shared_pointer & other) - { - std::swap(pointer, other.pointer); - std::swap(ref_count, other.ref_count); - } - - /** - * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. - * - * @return Returns the object owned by *this, equivalent to *get(). - */ - [[gnu::section(".stl_text")]] - auto operator*() const -> T & - { - return *pointer; - } - - /** - * @brief Member access operator. - * - * @return Returns a pointer to the object owned by *this, i.e. get(). - */ - [[gnu::section(".stl_text")]] - auto operator->() const -> T * - { - return pointer; - } - - /** - * @brief Returns a pointer to the managed object or nullptr if no object is owned. - * - * @return Pointer to the managed object or nullptr if no object is owned. - */ - [[gnu::section(".stl_text")]] - auto get() const -> T * - { - return pointer; - } - - /** - * @brief Returns the number of different shared_pointer 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 - * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, - * there are no other owners. - * - * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed - * object. - */ - [[gnu::section(".stl_text")]] - auto use_count() const -> std::size_t - { - if (pointer != nullptr) - { - return *ref_count; - } - - return 0; - } - - /** - * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. - * - * @return true if *this owns an object, false otherwise. - */ - [[gnu::section(".stl_text")]] - explicit operator bool() const - { - return pointer != nullptr; - } - - /** - * @brief Defaulted three-way comparator operator. - */ - [[gnu::section(".stl_text")]] - auto operator<=>(const shared_pointer & other) const = default; - - private: - /** - * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. - */ - [[gnu::section(".stl_text")]] - auto cleanup() -> void - { - if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) - { - delete pointer; - delete ref_count; - } - } - - T * pointer; ///< The managed object. - std::atomic * ref_count; ///< Reference count. - }; - - /** - * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls - * lhs.swap(rhs). - * - * @tparam T Type of the managed object. - * @param lhs, rhs Smart pointers whose contents to swap. - */ - template - auto swap(shared_pointer & lhs, shared_pointer & 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 - * 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(new T(std::forward(args)...)). - * - * @tparam T Type of the managed object. - * @tparam Args Argument types for T's constructor. - * @param args List of arguments with which an instance of T will be constructed. - * @returns Shared_pointer of an instance of type T. - */ - template - auto make_shared(Args &&... args) -> shared_pointer - { - return shared_pointer(new T(std::forward(args)...)); - } -} // namespace kstd - -#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/unique_pointer.hpp b/libs/kstd/include/kstd/unique_pointer.hpp deleted file mode 100644 index 2861646..0000000 --- a/libs/kstd/include/kstd/unique_pointer.hpp +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef KSTD_UNIQUE_POINTER_HPP -#define KSTD_UNIQUE_POINTER_HPP - -#include - -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. - * - * @tparam T Type of the managed object. - */ - template - struct unique_pointer - { - /** - * @brief Constructor. - * - * @param ptr A pointer to an object to manage (default is nullptr). - */ - [[gnu::section(".stl_text")]] - explicit unique_pointer(T * ptr = nullptr) - : pointer(ptr) - { - // Nothing to do. - } - - /** - * @brief Destructor that deletes the managed object. - */ - [[gnu::section(".stl_text")]] - ~unique_pointer() - { - delete pointer; - } - - /** - * @brief Deleted copy constructor to enforce unique ownership. - */ - unique_pointer(const unique_pointer &) = delete; - - /** - * @brief Deleted copy assignment operator to enforce unique ownership. - */ - auto operator=(const unique_pointer &) -> unique_pointer & = delete; - - /** - * @brief Move constructor. - * - * @param other Unique pointer to move from. - */ - [[gnu::section(".stl_text")]] - unique_pointer(unique_pointer && other) noexcept - : pointer(other.pointer) - { - other.pointer = nullptr; - } - - /** - * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). - * - * @param other Smart pointer from which ownership will be transferred. - * @return Reference to this unique pointer. - */ - [[gnu::section(".stl_text")]] - auto operator=(unique_pointer && other) noexcept -> unique_pointer & - { - if (this != &other) - { - delete pointer; - pointer = other.pointer; - other.pointer = nullptr; - } - return *this; - } - - /** - * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. - * - * @return Returns the object owned by *this, equivalent to *get(). - */ - [[gnu::section(".stl_text")]] - auto operator*() const -> T & - { - return *pointer; - } - - /** - * @brief Member access operator. - * - * @return Returns a pointer to the object owned by *this, i.e. get(). - */ - [[gnu::section(".stl_text")]] - auto operator->() const -> T * - { - return pointer; - } - - /** - * @brief Returns a pointer to the managed object or nullptr if no object is owned. - * - * @return Pointer to the managed object or nullptr if no object is owned. - */ - [[gnu::section(".stl_text")]] - auto get() const -> T * - { - return pointer; - } - - /** - * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. - * - * @return true if *this owns an object, false otherwise. - */ - [[gnu::section(".stl_text")]] - explicit operator bool() const noexcept - { - return pointer != nullptr; - } - - /** - * @brief Releases the ownership of the managed object, if any. - * get() returns nullptr after the call. - * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). - * - * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be - * returned by get() before the call. - */ - [[gnu::section(".stl_text")]] - auto release() -> T * - { - T * temp = pointer; - pointer = nullptr; - return temp; - } - - /** - * @brief Replaces the managed object. - * - * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, - * except where provided as a compiler extension or as a debugging assert. Note that code such as - * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. - * - * @param ptr Pointer to a new object to manage (default = nullptr). - */ - [[gnu::section(".stl_text")]] - auto reset(T * ptr = nullptr) -> void - { - delete pointer; - pointer = ptr; - } - - /** - * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. - * - * @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 - { - using std::swap; - swap(pointer, other.pointer); - } - - /** - * @brief Defaulted three-way comparator operator. - */ - [[gnu::section(".stl_text")]] - auto operator<=>(const unique_pointer & other) const = default; - - private: - T * pointer; ///< The managed pointer. - }; - - /** - * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls - * lhs.swap(rhs). - * - * @tparam T Type of the managed object. - * @param lhs, rhs Smart pointers whose contents to swap. - */ - template - auto swap(unique_pointer & lhs, unique_pointer & 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 - * 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(new T(std::forward(args)...)). - * - * @tparam T Type of the managed object. - * @tparam Args Argument types for T's constructor. - * @param args List of arguments with which an instance of T will be constructed. - * @returns Unique_pointer of an instance of type T. - */ - template - auto make_unique(Args &&... args) -> unique_pointer - { - return unique_pointer(new T(std::forward(args)...)); - } -} // namespace kstd - -#endif \ No newline at end of file -- cgit v1.2.3 From 833738f7023324172dbb0922fe1be9ad9cc88330 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:35:38 +0000 Subject: libs: rename kstd headers to be more STL like --- .vscode/settings.json | 10 +- libs/kstd/CMakeLists.txt | 9 +- libs/kstd/include/kstd/memory | 7 + libs/kstd/include/kstd/memory.hpp | 7 - libs/kstd/include/kstd/mutex | 60 ++++ libs/kstd/include/kstd/mutex.hpp | 60 ---- libs/kstd/include/kstd/stack | 213 ++++++++++++++ libs/kstd/include/kstd/stack.hpp | 213 -------------- libs/kstd/include/kstd/vector | 596 ++++++++++++++++++++++++++++++++++++++ libs/kstd/include/kstd/vector.hpp | 596 -------------------------------------- libs/kstd/src/mutex.cpp | 2 +- 11 files changed, 890 insertions(+), 883 deletions(-) create mode 100644 libs/kstd/include/kstd/memory delete mode 100644 libs/kstd/include/kstd/memory.hpp create mode 100644 libs/kstd/include/kstd/mutex delete mode 100644 libs/kstd/include/kstd/mutex.hpp create mode 100644 libs/kstd/include/kstd/stack delete mode 100644 libs/kstd/include/kstd/stack.hpp create mode 100644 libs/kstd/include/kstd/vector delete mode 100644 libs/kstd/include/kstd/vector.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 6178035..e8e872e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,12 +7,12 @@ "--query-driver=/opt/toolchain/bin/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 diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index a29fac8..b0abaaf 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -9,7 +9,14 @@ target_sources("kstd" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES - "include/kstd/mutex.hpp" + "include/kstd/bits/os.hpp" + "include/kstd/bits/shared_ptr.hpp" + "include/kstd/bits/unique_ptr.hpp" + + "include/kstd/memory" + "include/kstd/mutex" + "include/kstd/stack" + "include/kstd/vector" ) target_include_directories("kstd" PUBLIC 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/libs/kstd/include/kstd/memory.hpp b/libs/kstd/include/kstd/memory.hpp deleted file mode 100644 index cab2fba..0000000 --- a/libs/kstd/include/kstd/memory.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#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/libs/kstd/include/kstd/mutex b/libs/kstd/include/kstd/mutex new file mode 100644 index 0000000..cf8549f --- /dev/null +++ b/libs/kstd/include/kstd/mutex @@ -0,0 +1,60 @@ +#ifndef KSTD_MUTEX_HPP +#define KSTD_MUTEX_HPP + +#include + +namespace kstd +{ + /** + * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in + * use by another thread or not. + */ + struct mutex + { + /** + * @brief Defaulted constructor. + */ + mutex() = default; + + /** + * @brief Defaulted destructor. + */ + ~mutex() = default; + + /** + * @brief Deleted copy constructor. + */ + mutex(const mutex &) = delete; + + /** + * @brief Deleted assignment operator. + */ + mutex & operator=(const mutex &) = delete; + + /** + * @brief Lock the mutex (blocks for as long as it is not available). + */ + [[gnu::section(".stl_text")]] + auto lock() -> void; + + /** + * @brief Try to lock the mutex (non-blocking). + * + * @return True if lock has been acquired and false otherwise. + */ + [[gnu::section(".stl_text")]] + auto try_lock() -> bool; + + /** + * @brief Unlock the mutex. + */ + [[gnu::section(".stl_text")]] + auto unlock() -> void; + + private: + std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. + }; + +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/mutex.hpp b/libs/kstd/include/kstd/mutex.hpp deleted file mode 100644 index cf8549f..0000000 --- a/libs/kstd/include/kstd/mutex.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef KSTD_MUTEX_HPP -#define KSTD_MUTEX_HPP - -#include - -namespace kstd -{ - /** - * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in - * use by another thread or not. - */ - struct mutex - { - /** - * @brief Defaulted constructor. - */ - mutex() = default; - - /** - * @brief Defaulted destructor. - */ - ~mutex() = default; - - /** - * @brief Deleted copy constructor. - */ - mutex(const mutex &) = delete; - - /** - * @brief Deleted assignment operator. - */ - mutex & operator=(const mutex &) = delete; - - /** - * @brief Lock the mutex (blocks for as long as it is not available). - */ - [[gnu::section(".stl_text")]] - auto lock() -> void; - - /** - * @brief Try to lock the mutex (non-blocking). - * - * @return True if lock has been acquired and false otherwise. - */ - [[gnu::section(".stl_text")]] - auto try_lock() -> bool; - - /** - * @brief Unlock the mutex. - */ - [[gnu::section(".stl_text")]] - auto unlock() -> void; - - private: - std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. - }; - -} // namespace kstd - -#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/stack b/libs/kstd/include/kstd/stack new file mode 100644 index 0000000..8c702cf --- /dev/null +++ b/libs/kstd/include/kstd/stack @@ -0,0 +1,213 @@ +#ifndef KSTD_STACK_HPP +#define KSTD_STACK_HPP + +#include "kstd/vector.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the stack instance should contain. + * @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> + struct stack + { + using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. + using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. + using size_type = Container::size_type; ///< Type of the size in the underlying container. + using reference = Container::reference; ///< Type of reference to the elements. + using const_reference = Container::const_reference; ///< Type of constant reference to the elements. + + /** + * @brief Default Constructor. + */ + stack() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + [[gnu::section(".stl_text")]] + explicit stack(size_type n, value_type initial = value_type{}) + : _container(n, initial) + { + // Nothing to do. + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + [[gnu::section(".stl_text")]] + explicit stack(InputIterator first, InputIterator last) + : _container(first, last) + { + // Nothing to do. + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + [[gnu::section(".stl_text")]] + explicit stack(std::initializer_list initalizer_list) + : _container(initalizer_list) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all + * elements from it. + * + * @param other Other instance of stack we want to copy the data from. + */ + [[gnu::section(".stl_text")]] + stack(stack const & other) + : _container(other) + { + // Nothing to do. + } + + /** + * @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 & operator=(stack const & other) + { + _container = other; + } + + /** + * @brief Destructor. + */ + ~stack() = default; + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _container.size(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() -> reference + { + return _container.back(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() const -> const_reference + { + return _container.back(); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push(U && value) -> void + { + _container.push_back(std::forward(value)); + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace(Args &&... args) -> reference + { + _container.emplace_back(std::forward(args)...); + } + + /** + * @brief Removes the last element of the container. + * + * @note Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop() -> void + { + _container.pop_back(); + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _container.empty(); + } + + private: + container_type _container = {}; ///< Underlying container used by the stack to actually save the data. + }; + +} // namespace kstd + +#endif diff --git a/libs/kstd/include/kstd/stack.hpp b/libs/kstd/include/kstd/stack.hpp deleted file mode 100644 index 8c702cf..0000000 --- a/libs/kstd/include/kstd/stack.hpp +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef KSTD_STACK_HPP -#define KSTD_STACK_HPP - -#include "kstd/vector.hpp" - -#include - -namespace kstd -{ - /** - * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the stack instance should contain. - * @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> - struct stack - { - using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. - using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. - using size_type = Container::size_type; ///< Type of the size in the underlying container. - using reference = Container::reference; ///< Type of reference to the elements. - using const_reference = Container::const_reference; ///< Type of constant reference to the elements. - - /** - * @brief Default Constructor. - */ - stack() = default; - - /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value. - * - * @param n Amount of elements we want to create and set the given value for. - * @param initial Inital value of all elements in the underlying data array. - */ - [[gnu::section(".stl_text")]] - explicit stack(size_type n, value_type initial = value_type{}) - : _container(n, initial) - { - // Nothing to do. - } - - /** - * @brief Constructs data by copying all element from the given exclusive range. - * - * @tparam InputIterator Template that should have atleast input iterator characteristics. - * @param first Input iterator to the first element in the range we want to copy from. - * @param last Input iterator to one past the last element in the range we want to copy from. - */ - template - [[gnu::section(".stl_text")]] - explicit stack(InputIterator first, InputIterator last) - : _container(first, last) - { - // Nothing to do. - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - [[gnu::section(".stl_text")]] - explicit stack(std::initializer_list initalizer_list) - : _container(initalizer_list) - { - // Nothing to do. - } - - /** - * @brief Copy constructor. - * - * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all - * elements from it. - * - * @param other Other instance of stack we want to copy the data from. - */ - [[gnu::section(".stl_text")]] - stack(stack const & other) - : _container(other) - { - // Nothing to do. - } - - /** - * @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 & operator=(stack const & other) - { - _container = other; - } - - /** - * @brief Destructor. - */ - ~stack() = default; - - /** - * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - [[gnu::section(".stl_text")]] - auto size() const -> size_type - { - return _container.size(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto top() -> reference - { - return _container.back(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto top() const -> const_reference - { - return _container.back(); - } - - /** - * @brief Appends the given element value to the end of the container. The element is assigned through the - * assignment operator of the template type. The value is forwarded to the constructor as - * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). - * - * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, - * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. - * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @param value The value of the element to append. - */ - template - [[gnu::section(".stl_text")]] - auto push(U && value) -> void - { - _container.push_back(std::forward(value)); - } - - /** - * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the - * template type. The arguments args... are forwarded to the constructor as std::forward(args).... - * - * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case - * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only - * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - [[gnu::section(".stl_text")]] - auto emplace(Args &&... args) -> reference - { - _container.emplace_back(std::forward(args)...); - } - - /** - * @brief Removes the last element of the container. - * - * @note Calling pop_back on an empty container results in halting the - * further execution. Iterators and references to the last element are invalidated. The end() - * iterator is also invalidated. - */ - [[gnu::section(".stl_text")]] - auto pop() -> void - { - _container.pop_back(); - } - - /** - * @brief Wheter there are currently any items this container or not. - * - * @return True if there are no elements, false if there are. - */ - [[gnu::section(".stl_text")]] - auto empty() const -> bool - { - return _container.empty(); - } - - private: - container_type _container = {}; ///< Underlying container used by the stack to actually save the data. - }; - -} // namespace kstd - -#endif diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector new file mode 100644 index 0000000..1009e81 --- /dev/null +++ b/libs/kstd/include/kstd/vector @@ -0,0 +1,596 @@ +#ifndef KSTD_VECTOR_HPP +#define KSTD_VECTOR_HPP + +#include "bits/os.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the vector instance should contain. + */ + template + struct vector + { + using value_type = T; ///< Type of the elements contained in the container. + using size_type = std::size_t; ///< Type of the size in the container. + using reference = value_type &; ///< Type of reference to the elements. + using const_reference = value_type const &; ///< Type of constant reference to the elements. + using pointer = value_type *; ///< Type of pointer to the elements. + using const_pointer = value_type const *; ///< Type of constant pointer to the elements. + + /** + * @brief Default Constructor. + */ + vector() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + explicit vector(size_type n, value_type initial = value_type{}) + : _size(n) + , _capacity(n) + , _data(new value_type[_capacity]{}) + { + std::ranges::fill(*this, initial); + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + explicit vector(InputIterator first, InputIterator last) + : _size(std::distance(first, last)) + , _capacity(std::distance(first, last)) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(first, last, _data); + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + explicit vector(std::initializer_list initalizer_list) + : _size(initalizer_list.size()) + , _capacity(initalizer_list.size()) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(initalizer_list, _data); + } + + /** + * @brief Copy constructor. + * + * @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. + */ + vector(vector const & other) + : _size(other._size) + , _capacity(other._capacity) + { + delete[] _data; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + } + + /** + * @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")]] + vector & operator=(vector const & other) + { + delete[] _data; + _size = other._size; + _capacity = other._capacity; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + return *this; + } + + /** + * @brief Destructor. + */ + ~vector() { delete[] _data; } + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _size; + } + + /** + * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we + * exactly require to decrease the amount of allocations and deallocation to improve speed. + * + * @return Current amount of space the vector has for elements. + */ + [[gnu::section(".stl_text")]] + auto capacity() const -> size_type + { + return _capacity; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) -> reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) const -> const_reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) -> reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) const -> const_reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push_back(U && value) -> void + { + increase_capacity_if_full(); + _data[_size] = std::forward(value); + (void)_size++; + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace_back(Args &&... args) -> value_type & + { + increase_capacity_if_full(); + _data[_size] = value_type{std::forward(args)...}; + auto const index = _size++; + return _data[index]; + } + + /** + * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop_back() -> void + { + throw_if_empty(); + (void)_size--; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() noexcept -> pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() const noexcept -> const_pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto cbegin() const noexcept -> const_pointer + { + return begin(); + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() noexcept -> pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() const noexcept -> const_pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto crbegin() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() noexcept -> pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() const noexcept -> const_pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto cend() const noexcept -> const_pointer + { + return end(); + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() noexcept -> pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() const noexcept -> const_pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto crend() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() -> pointer + { + return _data; + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() const -> const_pointer + { + return _data; + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() -> reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() const -> const_reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() -> reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() const -> const_reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without + * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current + * capacity(), new storage is allocated, otherwise the function does nothing. + * + * reserve() does not change the size of the vector. + * + * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the + * elements are invalidated. Otherwise, no iterators or references are invalidated. + * + * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of + * the vector greater than the value of capacity(). + * + * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for + * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing + * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and + * decreased performance. For example, a function that receives an arbitrary vector by reference and appends + * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage + * characteristics. + * + * When inserting a range, the range version of insert() is generally preferable as it preserves the correct + * capacity growth behavior, unlike reserve() followed by a series of push_back()s. + * + * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. + * + * @param new_capacity New capacity of the vector, in number of elements + */ + [[gnu::section(".stl_text")]] + auto reserve(size_type new_capacity) -> void + { + if (new_capacity <= _capacity) + { + return; + } + + _capacity = new_capacity; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). + * + * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are + * invalidated. If no reallocation occurs, no iterators or references are invalidated. + */ + [[gnu::section(".stl_text")]] + auto shrink_to_fit() -> void + { + if (_size == _capacity) + { + return; + } + + _capacity = _size; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _size <= 0; + } + + private: + /** + * @brief Halts the execution of the application if the data container is currently empty. + */ + auto throw_if_empty() const -> void + { + if (empty()) + { + os::panic("[Vector] Attempted to access element of currently empty vector"); + } + } + + auto throw_if_out_of_range(size_type index) const -> void + { + if (index >= _size) + { + os::panic("[Vector] Attempted to read element at invalid index"); + } + } + + /** + * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential + * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is + * normally perferable for the cache. + */ + auto increase_capacity_if_full() -> void + { + if (_size == _capacity) + { + reserve(_capacity == 0U ? 1U : _capacity * 2U); + } + } + + size_type _size = {}; ///< Amount of elements in the underlying data container + size_type _capacity = {}; ///< Amount of space for elements in the underlying data container + value_type * _data = {}; ///< Pointer to the first element in the underlying data container + }; + +} // namespace kstd + +#endif diff --git a/libs/kstd/include/kstd/vector.hpp b/libs/kstd/include/kstd/vector.hpp deleted file mode 100644 index 1009e81..0000000 --- a/libs/kstd/include/kstd/vector.hpp +++ /dev/null @@ -1,596 +0,0 @@ -#ifndef KSTD_VECTOR_HPP -#define KSTD_VECTOR_HPP - -#include "bits/os.hpp" - -#include - -namespace kstd -{ - /** - * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the vector instance should contain. - */ - template - struct vector - { - using value_type = T; ///< Type of the elements contained in the container. - using size_type = std::size_t; ///< Type of the size in the container. - using reference = value_type &; ///< Type of reference to the elements. - using const_reference = value_type const &; ///< Type of constant reference to the elements. - using pointer = value_type *; ///< Type of pointer to the elements. - using const_pointer = value_type const *; ///< Type of constant pointer to the elements. - - /** - * @brief Default Constructor. - */ - vector() = default; - - /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value. - * - * @param n Amount of elements we want to create and set the given value for. - * @param initial Inital value of all elements in the underlying data array. - */ - explicit vector(size_type n, value_type initial = value_type{}) - : _size(n) - , _capacity(n) - , _data(new value_type[_capacity]{}) - { - std::ranges::fill(*this, initial); - } - - /** - * @brief Constructs data by copying all element from the given exclusive range. - * - * @tparam InputIterator Template that should have atleast input iterator characteristics. - * @param first Input iterator to the first element in the range we want to copy from. - * @param last Input iterator to one past the last element in the range we want to copy from. - */ - template - explicit vector(InputIterator first, InputIterator last) - : _size(std::distance(first, last)) - , _capacity(std::distance(first, last)) - , _data(new value_type[_capacity]{}) - { - std::ranges::copy(first, last, _data); - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - explicit vector(std::initializer_list initalizer_list) - : _size(initalizer_list.size()) - , _capacity(initalizer_list.size()) - , _data(new value_type[_capacity]{}) - { - std::ranges::copy(initalizer_list, _data); - } - - /** - * @brief Copy constructor. - * - * @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. - */ - vector(vector const & other) - : _size(other._size) - , _capacity(other._capacity) - { - delete[] _data; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - } - - /** - * @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")]] - vector & operator=(vector const & other) - { - delete[] _data; - _size = other._size; - _capacity = other._capacity; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - return *this; - } - - /** - * @brief Destructor. - */ - ~vector() { delete[] _data; } - - /** - * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - [[gnu::section(".stl_text")]] - auto size() const -> size_type - { - return _size; - } - - /** - * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we - * exactly require to decrease the amount of allocations and deallocation to improve speed. - * - * @return Current amount of space the vector has for elements. - */ - [[gnu::section(".stl_text")]] - auto capacity() const -> size_type - { - return _capacity; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Does not do any bounds checks use at() for that. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto operator[](size_type index) -> reference - { - return _data[index]; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Does not do any bounds checks use at() for that. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto operator[](size_type index) const -> const_reference - { - return _data[index]; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto at(size_type index) -> reference - { - throw_if_out_of_range(index); - return this->operator[](index); - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto at(size_type index) const -> const_reference - { - throw_if_out_of_range(index); - return this->operator[](index); - } - - /** - * @brief Appends the given element value to the end of the container. The element is assigned through the - * assignment operator of the template type. The value is forwarded to the constructor as - * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). - * - * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, - * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. - * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @param value The value of the element to append. - */ - template - [[gnu::section(".stl_text")]] - auto push_back(U && value) -> void - { - increase_capacity_if_full(); - _data[_size] = std::forward(value); - (void)_size++; - } - - /** - * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the - * template type. The arguments args... are forwarded to the constructor as std::forward(args).... - * - * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case - * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only - * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - [[gnu::section(".stl_text")]] - auto emplace_back(Args &&... args) -> value_type & - { - increase_capacity_if_full(); - _data[_size] = value_type{std::forward(args)...}; - auto const index = _size++; - return _data[index]; - } - - /** - * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the - * further execution. Iterators and references to the last element are invalidated. The end() - * iterator is also invalidated. - */ - [[gnu::section(".stl_text")]] - auto pop_back() -> void - { - throw_if_empty(); - (void)_size--; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto begin() noexcept -> pointer - { - return _data; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto begin() const noexcept -> const_pointer - { - return _data; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto cbegin() const noexcept -> const_pointer - { - return begin(); - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto rbegin() noexcept -> pointer - { - return _data + _size - 1; - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto rbegin() const noexcept -> const_pointer - { - return _data + _size - 1; - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto crbegin() const noexcept -> const_pointer - { - return rbegin(); - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto end() noexcept -> pointer - { - return _data + _size; - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto end() const noexcept -> const_pointer - { - return _data + _size; - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto cend() const noexcept -> const_pointer - { - return end(); - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto rend() noexcept -> pointer - { - return _data + size() - 1; - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto rend() const noexcept -> const_pointer - { - return _data + size() - 1; - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto crend() const noexcept -> const_pointer - { - return rbegin(); - } - - /** - * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range - * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable - * in that case). - * - * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal - * to the address of the first element. - */ - [[gnu::section(".stl_text")]] - auto data() -> pointer - { - return _data; - } - - /** - * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range - * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable - * in that case). - * - * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal - * to the address of the first element. - */ - [[gnu::section(".stl_text")]] - auto data() const -> const_pointer - { - return _data; - } - - /** - * @brief Returns a reference to the first element in the container. Calling front on an empty container causes - * undefined behavior. - * - * @return Reference to the first element. - */ - [[gnu::section(".stl_text")]] - auto front() -> reference - { - throw_if_empty(); - return *begin(); - } - - /** - * @brief Returns a reference to the first element in the container. Calling front on an empty container causes - * undefined behavior. - * - * @return Reference to the first element. - */ - [[gnu::section(".stl_text")]] - auto front() const -> const_reference - { - throw_if_empty(); - return *begin(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto back() -> reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto back() const -> const_reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without - * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current - * capacity(), new storage is allocated, otherwise the function does nothing. - * - * reserve() does not change the size of the vector. - * - * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the - * elements are invalidated. Otherwise, no iterators or references are invalidated. - * - * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of - * the vector greater than the value of capacity(). - * - * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for - * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing - * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and - * decreased performance. For example, a function that receives an arbitrary vector by reference and appends - * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage - * characteristics. - * - * When inserting a range, the range version of insert() is generally preferable as it preserves the correct - * capacity growth behavior, unlike reserve() followed by a series of push_back()s. - * - * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. - * - * @param new_capacity New capacity of the vector, in number of elements - */ - [[gnu::section(".stl_text")]] - auto reserve(size_type new_capacity) -> void - { - if (new_capacity <= _capacity) - { - return; - } - - _capacity = new_capacity; - value_type * temp = new value_type[_capacity]{}; - std::ranges::copy(begin(), end(), temp); - delete[] _data; - _data = temp; - } - - /** - * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). - * - * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are - * invalidated. If no reallocation occurs, no iterators or references are invalidated. - */ - [[gnu::section(".stl_text")]] - auto shrink_to_fit() -> void - { - if (_size == _capacity) - { - return; - } - - _capacity = _size; - value_type * temp = new value_type[_capacity]{}; - std::ranges::copy(begin(), end(), temp); - delete[] _data; - _data = temp; - } - - /** - * @brief Wheter there are currently any items this container or not. - * - * @return True if there are no elements, false if there are. - */ - [[gnu::section(".stl_text")]] - auto empty() const -> bool - { - return _size <= 0; - } - - private: - /** - * @brief Halts the execution of the application if the data container is currently empty. - */ - auto throw_if_empty() const -> void - { - if (empty()) - { - os::panic("[Vector] Attempted to access element of currently empty vector"); - } - } - - auto throw_if_out_of_range(size_type index) const -> void - { - if (index >= _size) - { - os::panic("[Vector] Attempted to read element at invalid index"); - } - } - - /** - * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential - * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is - * normally perferable for the cache. - */ - auto increase_capacity_if_full() -> void - { - if (_size == _capacity) - { - reserve(_capacity == 0U ? 1U : _capacity * 2U); - } - } - - size_type _size = {}; ///< Amount of elements in the underlying data container - size_type _capacity = {}; ///< Amount of space for elements in the underlying data container - value_type * _data = {}; ///< Pointer to the first element in the underlying data container - }; - -} // namespace kstd - -#endif diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp index cfb1c84..137ebc0 100644 --- a/libs/kstd/src/mutex.cpp +++ b/libs/kstd/src/mutex.cpp @@ -1,4 +1,4 @@ -#include "kstd/mutex.hpp" +#include "kstd/mutex" namespace kstd { -- cgit v1.2.3 From 71bb11508020a55c5636f05136bd03059ddc33ed Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:41:53 +0000 Subject: arch: move and improve asm_pointer --- arch/include/arch/asm_pointer.hpp | 56 +++++++++++++++++++++++++++++ kern/include/kern/asm_pointer.hpp | 76 --------------------------------------- 2 files changed, 56 insertions(+), 76 deletions(-) create mode 100644 arch/include/arch/asm_pointer.hpp delete mode 100644 kern/include/kern/asm_pointer.hpp diff --git a/arch/include/arch/asm_pointer.hpp b/arch/include/arch/asm_pointer.hpp new file mode 100644 index 0000000..c867d8f --- /dev/null +++ b/arch/include/arch/asm_pointer.hpp @@ -0,0 +1,56 @@ +#ifndef TEACHOS_MEMORY_ASM_POINTER_HPP +#define TEACHOS_MEMORY_ASM_POINTER_HPP + +#include + +namespace teachos::arch +{ + + /** + * @brief A pointer that is defined in some assembly source file. + * + * @tparam Type The type of the pointer + * @since 0.0.1 + */ + template + struct asm_pointer + { + 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_pointer() = delete; + asm_pointer(asm_pointer const &) = delete; + asm_pointer(asm_pointer &&) = delete; + + auto constexpr operator=(asm_pointer const &) = delete; + auto constexpr operator=(asm_pointer &&) = delete; + + auto get() const noexcept -> pointer { return m_ptr; } + + auto constexpr operator+(std::ptrdiff_t offset) const noexcept -> pointer + { + return std::bit_cast(m_ptr) + offset; + } + + auto constexpr operator*() noexcept -> reference { return *(std::bit_cast(m_ptr)); } + + auto constexpr operator*() const noexcept -> const_reference { return *(std::bit_cast(m_ptr)); } + + auto constexpr operator[](std::ptrdiff_t offset) noexcept -> reference { return *(*this + offset); } + + auto constexpr operator[](std::ptrdiff_t offset) const noexcept -> const_reference { return *(*this + offset); } + + auto constexpr operator->() noexcept -> pointer { return m_ptr; } + + auto constexpr operator->() const noexcept -> const_pointer { return m_ptr; } + + private: + pointer m_ptr; + }; + +} // namespace teachos::arch + +#endif // TEACHOS_MEMORY_ASM_POINTER_HPP diff --git a/kern/include/kern/asm_pointer.hpp b/kern/include/kern/asm_pointer.hpp deleted file mode 100644 index 4c25658..0000000 --- a/kern/include/kern/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 - 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 - struct asm_pointer - { - /** @copydoc asm_pointer::asm_pointer */ - constexpr asm_pointer(Type const & pointer) - : m_pointer{&pointer} - { - } - - /** @copydoc asm_pointer::operator*() */ - auto constexpr operator*() -> Type const & { return *m_pointer; } - /** @copydoc asm_pointer::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 -- cgit v1.2.3 From 3a47a8bd0edcfa3aa03562d0a5c390ef85ad0c6b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:08:02 +0000 Subject: x86_64: move basic text output implementation --- arch/x86_64/CMakeLists.txt | 9 ++ arch/x86_64/include/arch/video/vga/io.hpp | 39 ------- arch/x86_64/include/arch/video/vga/text.hpp | 169 --------------------------- arch/x86_64/include/x86_64/vga/io.hpp | 39 +++++++ arch/x86_64/include/x86_64/vga/text.hpp | 173 ++++++++++++++++++++++++++++ arch/x86_64/src/io.cpp | 28 ++--- arch/x86_64/src/vga/text.cpp | 66 +++++++++++ arch/x86_64/src/video/vga/text.cpp | 66 ----------- kern/src/main.cpp | 3 + 9 files changed, 304 insertions(+), 288 deletions(-) delete mode 100644 arch/x86_64/include/arch/video/vga/io.hpp delete mode 100644 arch/x86_64/include/arch/video/vga/text.hpp create mode 100644 arch/x86_64/include/x86_64/vga/io.hpp create mode 100644 arch/x86_64/include/x86_64/vga/text.hpp create mode 100644 arch/x86_64/src/vga/text.cpp delete mode 100644 arch/x86_64/src/video/vga/text.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index dd54b39..86c9559 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -7,6 +7,7 @@ target_include_directories("arch-x86_64" PUBLIC target_link_libraries("arch-x86_64" PUBLIC "arch::any" + "os::kern" "libs::multiboot2" ) @@ -39,6 +40,14 @@ target_sources("arch-x86_64" PRIVATE "src/boot/multiboot.s" ) +#[============================================================================[ +# VGA Code +#]============================================================================] + +target_sources("arch-x86_64" PRIVATE + "src/vga/text.cpp" +) + # #[============================================================================[ # # The Kernel Library # #]============================================================================] 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 - -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 -#include -#include - -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 - concept Integral = std::is_integral_v; - - /** - * @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 - 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/vga/io.hpp b/arch/x86_64/include/x86_64/vga/io.hpp new file mode 100644 index 0000000..803dc21 --- /dev/null +++ b/arch/x86_64/include/x86_64/vga/io.hpp @@ -0,0 +1,39 @@ +#ifndef TEACHOS_X86_64_VGA_IO_HPP +#define TEACHOS_X86_64_VGA_IO_HPP + +#include "arch/io/port_io.hpp" + +#include + +namespace teachos::x86_64::vga::io +{ + 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 cursor_end = std::byte{0x0b}; + } // namespace registers + + }; // namespace crtc + +} // namespace teachos::x86_64::vga::io + +#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..267eae9 --- /dev/null +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -0,0 +1,173 @@ +#ifndef TEACHOS_X86_64_VIDEO_VGA_TEXT_HPP +#define TEACHOS_X86_64_VIDEO_VGA_TEXT_HPP + +#include +#include +#include + +namespace teachos::x86_64::vga::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 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 green foreground and black background. + */ + [[maybe_unused]] auto constexpr red_on_black = + attribute{color::red, 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 + concept Integral = std::is_integral_v; + + /** + * @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 + 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::x86_64::vga::text + +#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp index 8808dbb..5fb1c85 100644 --- a/arch/x86_64/src/io.cpp +++ b/arch/x86_64/src/io.cpp @@ -1,22 +1,22 @@ +#include "kern/print.hpp" +#include "x86_64/vga/text.hpp" + namespace teachos::arch::io { - // using x86_64::vga::text_mode::attributes; - // using x86_64::vga::text_mode::color; - - // namespace - // { - // auto constexpr error_attributes = - // attributes{.foreground = color::light_gray, .bright = true, .background = color::red, .blink = true}; - // } // namespace - auto init() -> void { - // kernel::set_print_handler([](auto text) { return x86_64::vga::text_mode::print(text); }); - // kernel::set_println_handler([](auto text) { return x86_64::vga::text_mode::println(text); }); - // kernel::set_print_error_handler([](auto text) { return x86_64::vga::text_mode::print(text, error_attributes); }); - // kernel::set_println_error_handler( - // [](auto text) { return x86_64::vga::text_mode::println(text, error_attributes); }); + teachos::set_print_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); + teachos::set_println_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); + + teachos::set_print_error_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); + teachos::set_println_error_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); + + teachos::println("[x86-64] Basic VGA text output initialized."); } } // namespace teachos::arch::io diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp new file mode 100644 index 0000000..9b7946d --- /dev/null +++ b/arch/x86_64/src/vga/text.cpp @@ -0,0 +1,66 @@ +#include "x86_64/vga/text.hpp" + +#include "arch/asm_pointer.hpp" +#include "x86_64/vga/io.hpp" + +#include +#include +#include +#include + +extern "C" teachos::arch::asm_pointer> vga_buffer_pointer; + +namespace teachos::x86_64::vga::text +{ + namespace + { + // auto constexpr DEFAULT_VGA_TEXT_BUFFER_ADDRESS = 0xB8000; + + auto buffer_offset = std::ptrdiff_t{}; + + auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; + auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + } // namespace + + auto clear(attribute attribute) -> void + { + buffer_offset = 0; + std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', attribute}); + } + + auto cursor(bool enabled) -> void + { + auto cursor_disable_byte = std::byte{!enabled} << 5; + + io::crtc::address_port::write(io::crtc::registers::cursor_start); + io::crtc::data_port::write(io::crtc::data_port::read() | cursor_disable_byte); + } + + auto newline() -> void + { + auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; + auto next_line = current_line + 1; + + if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT) + { + auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; + auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; + std::ranges::move(begin, end, vga_buffer_pointer.get()); + buffer_offset = current_line * DEFAULT_TEXT_BUFFER_WIDTH; + } + else + { + buffer_offset = next_line * DEFAULT_TEXT_BUFFER_WIDTH; + } + } + + auto write_char(char code_point, attribute attribute) -> void + { + vga_buffer_pointer[buffer_offset++] = 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::x86_64::vga::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 -#include -#include - -extern "C" std::pair * 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(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(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/kern/src/main.cpp b/kern/src/main.cpp index 5e1b6ea..b99fb37 100644 --- a/kern/src/main.cpp +++ b/kern/src/main.cpp @@ -1,10 +1,13 @@ #include "arch/io.hpp" #include "arch/memory.hpp" #include "kern/error.hpp" +#include "kern/print.hpp" auto main() -> int { teachos::arch::io::init(); + teachos::println("[OS] IO subsystem initialized."); + teachos::arch::memory::init(); teachos::panic("Architecture specific main returned!"); -- cgit v1.2.3 From 05ac8c2bdd000d27b38411db2223eabb649c318f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:29:10 +0000 Subject: build: reintroduce bootable ISO --- .vscode/launch.json | 2 +- .vscode/tasks.json | 4 ++-- CMakeLists.txt | 9 +++++++-- arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/io.cpp | 14 ++++++++++---- arch/x86_64/src/vga/text.cpp | 2 -- arch/x86_64/support/grub.cfg.in | 2 +- cmake/Modules/GenerateBootableIso.cmake | 22 ++++++++++++++++++++++ 8 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 cmake/Modules/GenerateBootableIso.cmake diff --git a/.vscode/launch.json b/.vscode/launch.json index 3b53048..7778c04 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "gdbpath": "x86_64-pc-elf-gdb", "cwd": "${workspaceFolder}", "preLaunchTask": "QEMU (gdb)", - "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/_kernel.elf", + "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.elf", "autorun": [ "-enable-pretty-printing", "-break-insert _start" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3b5ae9f..12ec2ea 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -17,7 +17,7 @@ "-d", "int,cpu_reset", "-cdrom", - "${command:cmake.buildDirectory}/teachos-${command:cmake.buildType}.iso" + "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.iso" ], "isBackground": true, "presentation": { @@ -52,7 +52,7 @@ "-display", "curses", "-cdrom", - "${command:cmake.buildDirectory}/teachos-${command:cmake.buildType}.iso" + "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.iso" ], "isBackground": true, "presentation": { diff --git a/CMakeLists.txt b/CMakeLists.txt index a00b043..27500ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,10 @@ project("kernel" LANGUAGES ASM C CXX ) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules") + +include("GenerateBootableIso") + #[============================================================================[ # Global Build System Configuration #]============================================================================] @@ -15,8 +19,6 @@ 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_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS NO) @@ -36,6 +38,9 @@ target_link_libraries("kernel" PRIVATE "os::kern" ) +target_generate_bootable_iso("kernel") + + # #[============================================================================[ # # Documentation # #]============================================================================] diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 5488073..728380d 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -105,7 +105,7 @@ mesage_long_mode_not_supported: * We need a pointer to our current position in the VGA text buffer. */ .global vga_buffer_pointer -vga_buffer_pointer: .long 0xb8000 +vga_buffer_pointer: .quad 0xb8000 /** * Code for the bootstrapping process. diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp index 5fb1c85..8e9e411 100644 --- a/arch/x86_64/src/io.cpp +++ b/arch/x86_64/src/io.cpp @@ -6,15 +6,21 @@ namespace teachos::arch::io auto init() -> void { + x86_64::vga::text::cursor(false); + teachos::set_print_handler( [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); - teachos::set_println_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); + teachos::set_println_handler([](auto text) { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + x86_64::vga::text::newline(); + }); teachos::set_print_error_handler( [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); - teachos::set_println_error_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); + teachos::set_println_error_handler([](auto text) { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + x86_64::vga::text::newline(); + }); teachos::println("[x86-64] Basic VGA text output initialized."); } diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 9b7946d..16abf08 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -14,8 +14,6 @@ namespace teachos::x86_64::vga::text { namespace { - // auto constexpr DEFAULT_VGA_TEXT_BUFFER_ADDRESS = 0xB8000; - auto buffer_offset = std::ptrdiff_t{}; auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; 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 /$ + multiboot2 /$ boot } \ No newline at end of file diff --git a/cmake/Modules/GenerateBootableIso.cmake b/cmake/Modules/GenerateBootableIso.cmake new file mode 100644 index 0000000..368dcf6 --- /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 "$/isofs/boot/grub/grub.cfg" + INPUT "arch/${CMAKE_SYSTEM_PROCESSOR}/support/grub.cfg.in" + ) + + add_custom_command(TARGET "${TARGET}" + POST_BUILD + COMMAND "${GRUB_MKRESCUE_EXE}" + "-o" + "$/${TARGET}.iso" + "$/isofs" + "$" + "2>/dev/null" + BYPRODUCTS "${PROJECT_BINARY_DIR}/$/${TARGET}.iso" + COMMENT "Creating bootable ISO image" + ) +endfunction() -- cgit v1.2.3 From 9b12522f37c3f8704e8f8ca8736689dbbf30ce8b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:35:43 +0000 Subject: cmake: introduce ELF utility module --- .vscode/launch.json | 2 +- CMakeLists.txt | 6 +++++- cmake/Modules/ElfTransformations.cmake | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 cmake/Modules/ElfTransformations.cmake diff --git a/.vscode/launch.json b/.vscode/launch.json index 7778c04..6739aa3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "gdbpath": "x86_64-pc-elf-gdb", "cwd": "${workspaceFolder}", "preLaunchTask": "QEMU (gdb)", - "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.elf", + "executable": "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.sym", "autorun": [ "-enable-pretty-printing", "-break-insert _start" diff --git a/CMakeLists.txt b/CMakeLists.txt index 27500ed..6f7d5a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ project("kernel" set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules") +include("ElfTransformations") include("GenerateBootableIso") #[============================================================================[ @@ -38,8 +39,11 @@ target_link_libraries("kernel" PRIVATE "os::kern" ) -target_generate_bootable_iso("kernel") +target_disassemble("kernel") +target_extract_debug_symbols("kernel") +target_strip("kernel") +target_generate_bootable_iso("kernel") # #[============================================================================[ # # Documentation 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" + "$" + "$/$.sym" + BYPRODUCTS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/${TARGET}.sym" + COMMENT "Extracting debug symbols from $ ..." + ) +endfunction() + +function(target_strip TARGET) + add_custom_command(TARGET "${TARGET}" + POST_BUILD + COMMAND "${CMAKE_STRIP}" + "$" + COMMENT "Stripping $ ..." + ) +endfunction() + +function(target_disassemble TARGET) + add_custom_command(TARGET "${TARGET}" + POST_BUILD + COMMAND "${CMAKE_OBJDUMP}" + "--disassemble" + "--visualize-jumps" + "--demangle" + "$" + ">$/$.dis" + BYPRODUCTS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/${TARGET}.dis" + COMMENT "Dumping disassembly for $ ..." + ) +endfunction() -- cgit v1.2.3 From b794fc9e4427f63aba624700af2e1df250aa41ef Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:38:04 +0000 Subject: cmake: remove lefover main configuration --- CMakeLists.txt | 104 ++++++--------------------------------------------------- 1 file changed, 10 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f7d5a8..9ddb4ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,13 @@ set(CMAKE_CXX_STANDARD "20") set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS NO) +add_compile_options( + "$<$:-Wall>" + "$<$:-Wextra>" + "$<$:-Werror>" + "$<$:-pedantic-errors>" +) + #[============================================================================[ # Global Build System Configuration #]============================================================================] @@ -45,9 +52,9 @@ target_strip("kernel") target_generate_bootable_iso("kernel") -# #[============================================================================[ -# # Documentation -# #]============================================================================] +#[============================================================================[ +# Documentation +#]============================================================================] # find_package("Doxygen") @@ -90,94 +97,3 @@ target_generate_bootable_iso("kernel") # "${PROJECT_BINARY_DIR}/docs" # ) -# #[============================================================================[ -# # Global Compiler Configuration -# #]============================================================================] - -# add_compile_options( -# "$<$:-Wall>" -# "$<$:-Wextra>" -# "$<$:-Werror>" -# "$<$:-pedantic-errors>" -# ) - -# #[============================================================================[ -# # Global Libraries -# #]============================================================================] - -# add_subdirectory("libs/kstd" EXCLUDE_FROM_ALL SYSTEM) -# add_subdirectory("libs/multiboot2" EXCLUDE_FROM_ALL SYSTEM) - -# #[============================================================================[ -# # 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 -# #]============================================================================] - -# add_library("_video" OBJECT) -# add_library("teachos::video" ALIAS "_video") - -# #[============================================================================[ -# # THE Memory Library -# #]============================================================================] - -# add_library("_memory" OBJECT) -# add_library("teachos::memory" ALIAS "_memory") - -# #[============================================================================[ -# # The Exception handling Library -# #]============================================================================] - -# add_library("_exception" OBJECT) -# add_library("teachos::exception" ALIAS "_exception") - -# #[============================================================================[ -# # 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 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::context_switching" -# "teachos::interrupt_handling" -# ) - -# #[============================================================================[ -# # Platform Specific Components -# #]============================================================================] - -# add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") -- cgit v1.2.3 From a832505d9696ae66248b53602d41637bef4868aa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 10:49:03 +0000 Subject: kernel: turn into a PIE --- CMakeLists.txt | 4 ++ CMakePresets.json | 2 +- arch/x86_64/src/boot/boot.s | 112 ++++++++++++++++++++++++++++++++------------ 3 files changed, 87 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ddb4ed..821640c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,10 @@ target_link_libraries("kernel" PRIVATE "os::kern" ) +target_link_options("kernel" PRIVATE + "-no-pie" +) + target_disassemble("kernel") target_extract_debug_symbols("kernel") target_strip("kernel") diff --git a/CMakePresets.json b/CMakePresets.json index b01208a..8943a4d 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -5,7 +5,7 @@ "name": "default", "binaryDir": "${sourceDir}/build", "generator": "Ninja Multi-Config", - "toolchainFile": "${workspaceFolder}/cmake/Platforms/x86_64.cmake", + "toolchainFile": "cmake/Platforms/x86_64.cmake", "cacheVariables": { "CMAKE_CONFIGURATION_TYPES": "Debug;MinSizeRel", "CMAKE_EXPORT_COMPILE_COMMANDS": "YES" diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 728380d..ada6426 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -71,16 +71,7 @@ stack_top: 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 +global_descriptor_table_end: /** * We are going to print some messages in case we panic during boot, so we are @@ -130,7 +121,12 @@ _panic: push %ebp mov %esp, %ebp - push message_prefix_panic + call .Lpanic_get_ip +.Lpanic_get_ip: + pop %eax + lea (message_prefix_panic - .Lpanic_get_ip)(%eax), %eax + + push %eax push $0x4f call _print add $8, %esp @@ -155,10 +151,17 @@ _print: push %ebx push %esi + push %edi + + call .Lprint_get_ip +.Lprint_get_ip: + pop %edi + lea (vga_buffer_pointer - .Lprint_get_ip)(%edi), %edi + mov 8(%ebp), %eax mov 12(%ebp), %ebx mov $0, %ecx - mov (vga_buffer_pointer), %esi + mov (%edi), %esi .Lprint_loop: mov (%ebx, %ecx), %dl @@ -171,9 +174,11 @@ _print: .Lupdate_vga_buffer_address: shl $1, %ecx - add %ecx, (vga_buffer_pointer) + add %ecx, %esi + mov %esi, (%edi) .Lprint_end: + pop %edi pop %esi pop %ebx mov %ebp, %esp @@ -187,7 +192,12 @@ _print: */ .global _start _start: - mov $stack_top, %esp + call .Lstart_get_ip +.Lstart_get_ip: + pop %esi + lea (stack_top - .Lstart_get_ip)(%esi), %ebx + + mov %ebx, %esp mov %esp, %ebp call assert_loaded_by_multiboot2_loader @@ -197,8 +207,19 @@ _start: call enable_paging call enable_sse - lgdt (global_descriptor_table_pointer) - jmp $global_descriptor_table_code, $_transition_to_long_mode + sub $10, %esp + lea (global_descriptor_table - .Lstart_get_ip)(%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 + + lea (_transition_to_long_mode - .Lstart_get_ip)(%esi), %eax + pushl $global_descriptor_table_code + pushl %eax + lret call halt @@ -217,7 +238,11 @@ assert_cpu_supports_long_mode: jz .Llong_mode_assertion_failed ret .Llong_mode_assertion_failed: - push $mesage_long_mode_not_supported + call .Lassert_cpu_supports_long_mode_fail_get_ip +.Lassert_cpu_supports_long_mode_fail_get_ip: + pop %eax + lea (mesage_long_mode_not_supported - .Lassert_cpu_supports_long_mode_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -245,7 +270,11 @@ assert_cpuid_instruction_is_supported: je .Lcpuid_assertion_fail ret .Lcpuid_assertion_fail: - push $message_cpuid_instruction_no_supported + call .Lassert_cpuid_instruction_is_supported_fail_get_ip +.Lassert_cpuid_instruction_is_supported_fail_get_ip: + pop %eax + lea (message_cpuid_instruction_no_supported - .Lassert_cpuid_instruction_is_supported_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -259,10 +288,18 @@ 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 */ + call .Lassert_loaded_by_multiboot2_loader_get_ip +.Lassert_loaded_by_multiboot2_loader_get_ip: + pop %eax + lea (multiboot_information_pointer - .Lassert_loaded_by_multiboot2_loader_get_ip)(%eax), %eax + mov %ebx, (%eax) /* Store the MBI pointer */ ret .Lmultiboot2_assertion_fail: - push $message_not_loaded_by_multiboot2 + call .Lassert_loaded_by_multiboot2_loader_fail_get_ip +.Lassert_loaded_by_multiboot2_loader_fail_get_ip: + pop %eax + lea (message_not_loaded_by_multiboot2 - .Lassert_loaded_by_multiboot2_loader_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -272,7 +309,10 @@ assert_loaded_by_multiboot2_loader: * set up for use. */ enable_paging: - mov $page_map_level_4, %eax + call .Lenable_paging_get_ip +.Lenable_paging_get_ip: + pop %eax +lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax mov %eax, %cr3 /* Enable Physical Address Extension */ @@ -316,37 +356,46 @@ enable_sse: * page map entries. */ prepare_page_maps: + call .Lprepare_page_maps_get_ip +.Lprepare_page_maps_get_ip: + pop %edi /* Map the P4 table recursively */ - mov $page_map_level_4, %eax + lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %eax + mov %eax, %ebx or $0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (page_map_level_4 + 511 * 8) + mov %eax, (511 * 8)(%ebx) /* Add an entry to the PML4, pointing to the PML3 */ - mov $page_map_level_3, %eax + lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %eax + lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %ebx or $0x3, %eax - mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) + mov %eax, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%ebx) /* Add an entry to the PML3, pointing to the PML2 */ - mov $page_map_level_2, %eax + lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %eax + lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %ebx or $0x3, %eax - mov %eax, (page_map_level_3 + ((0x0000000000100000 >> 30) & 0x1ff) * 8) + mov %eax, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%ebx) xor %ecx, %ecx - mov $_end_linear, %esi + push %esi + lea (_end_linear - .Lprepare_page_maps_get_ip)(%edi), %esi shr $21, %esi add $2, %esi .Lmap_pages: + lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %ebx mov $(1 << 21), %eax mul %ecx or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, page_map_level_2(,%ecx,8) + mov %eax, (%ebx,%ecx,8) inc %ecx cmp %esi, %ecx jne .Lmap_pages + pop %esi ret .section .boot_text, "ax", @progbits @@ -360,7 +409,10 @@ _transition_to_long_mode: mov %rax, %fs mov %rax, %gs - movl $0xb8000, (vga_buffer_pointer) + leaq vga_buffer_pointer(%rip), %rax + movl $0xb8000, (%rax) + + xor %rax, %rax call _init -- cgit v1.2.3 From 891ca8834122e55638d33a129baab7292b8ed6d0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 15 Jul 2025 16:31:59 +0000 Subject: kern: simplify print wrappers --- kern/src/print.cpp | 45 ++++++++++----------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/kern/src/print.cpp b/kern/src/print.cpp index 64e2c65..2c8539b 100644 --- a/kern/src/print.cpp +++ b/kern/src/print.cpp @@ -7,43 +7,18 @@ namespace teachos { namespace { - print_handler * current_print_handler{}; - println_handler * current_println_handler{}; - print_handler * current_print_error_handler{}; - println_handler * current_println_error_handler{}; - } // namespace - - auto print(std::string_view text) -> void - { - if (current_print_handler) - { - current_print_handler(text); - } - } - - auto println(std::string_view text) -> void - { - if (current_println_handler) - { - current_println_handler(text); - } - } + constinit auto noop = [](std::string_view) {}; - auto print_error(std::string_view text) -> void - { - if (current_print_error_handler) - { - current_print_error_handler(text); - } - } + constinit auto current_print_handler = static_cast(noop); + constinit auto current_println_handler = static_cast(noop); + constinit auto current_print_error_handler = static_cast(noop); + constinit auto current_println_error_handler = static_cast(noop); + } // namespace - auto println_error(std::string_view text) -> void - { - if (current_println_error_handler) - { - current_println_error_handler(text); - } - } + auto print(std::string_view text) -> void { current_print_handler(text); } + auto println(std::string_view text) -> void { current_println_handler(text); } + auto print_error(std::string_view text) -> void { current_print_error_handler(text); } + auto println_error(std::string_view text) -> void { current_println_error_handler(text); } auto set_print_handler(print_handler handler) -> print_handler * { -- cgit v1.2.3 From 14ed096fc5de6844cb116f3319c0d03043d26ea2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 17 Jul 2025 21:09:02 +0000 Subject: x86-64: prepare new architecture --- .clang-format | 18 ++- arch/x86_64/CMakeLists.txt | 8 ++ .../arch/memory/allocator/area_frame_allocator.hpp | 12 +- .../arch/memory/allocator/physical_frame.hpp | 86 ------------ arch/x86_64/include/x86_64/memory/address.hpp | 47 +++++++ arch/x86_64/include/x86_64/memory/frame.hpp | 95 +++++++++++++ .../include/x86_64/memory/region_allocator.hpp | 76 +++++++++++ arch/x86_64/scripts/x86-64-linker-script.txt | 150 +++++++++++++++++++++ arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/memory.cpp | 90 ++++++------- .../x86_64/src/memory/allocator/physical_frame.cpp | 24 ---- arch/x86_64/src/memory/region_allocator.cpp | 95 +++++++++++++ libs/multiboot2/include/multiboot2/impl/data.hpp | 6 +- .../include/multiboot2/impl/iterator.hpp | 5 +- 14 files changed, 538 insertions(+), 176 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/allocator/physical_frame.hpp create mode 100644 arch/x86_64/include/x86_64/memory/address.hpp create mode 100644 arch/x86_64/include/x86_64/memory/frame.hpp create mode 100644 arch/x86_64/include/x86_64/memory/region_allocator.hpp create mode 100644 arch/x86_64/scripts/x86-64-linker-script.txt delete mode 100644 arch/x86_64/src/memory/allocator/physical_frame.cpp create mode 100644 arch/x86_64/src/memory/region_allocator.cpp diff --git a/.clang-format b/.clang-format index d4da962..b32e8c9 100644 --- a/.clang-format +++ b/.clang-format @@ -40,15 +40,21 @@ DerivePointerAlignment: 'false' FixNamespaceComments: 'true' IncludeBlocks: Regroup IncludeCategories: - # Local Headers - - Regex: '"(.*/?)+/.+\.hpp"' + # Kernel Headers + - Regex: 'kern/[[:alnum:]._\/]+\.hpp' Priority: 100 + # Architecture Interface Headers + - Regex: 'arch/[[:alnum:]._\/]+\.hpp' + Priority: 110 + # Architecture Implementation Headers + - Regex: 'x86_64/[[:alnum:]._\/]+\.hpp' + Priority: 110 + # Library Headers + - Regex: '[[:alnum:]._\/]+\.hpp' + Priority: 300 # STL Headers - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' - Priority: 400 - # C Library Headers - - Regex: '<([[:alnum:]._]/*)+\.h>' - Priority: 300 + Priority: 900 IndentCaseLabels: 'true' IndentPPDirectives: None IndentWidth: '2' diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 86c9559..d1af777 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -40,6 +40,14 @@ target_sources("arch-x86_64" PRIVATE "src/boot/multiboot.s" ) +#[============================================================================[ +# Memory Code +#]============================================================================] + +target_sources("arch-x86_64" PRIVATE + "src/memory/region_allocator.cpp" +) + #[============================================================================[ # VGA Code #]============================================================================] 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 index 6cb5f56..a86c9b7 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -1,12 +1,12 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP +#ifndef TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP +#define TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP -#include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/multiboot/reader.hpp" +// #include "arch/memory/allocator/physical_frame.hpp" +// #include "arch/memory/multiboot/reader.hpp" #include -namespace teachos::arch::memory::allocator +namespace x86_64::memory { /** * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any @@ -62,6 +62,6 @@ namespace teachos::arch::memory::allocator physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; -} // namespace teachos::arch::memory::allocator +} // namespace x86_64::memory #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_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 -#include -#include - -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>; - -} // namespace teachos::arch::memory::allocator - -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/x86_64/memory/address.hpp b/arch/x86_64/include/x86_64/memory/address.hpp new file mode 100644 index 0000000..20e9655 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/address.hpp @@ -0,0 +1,47 @@ +#ifndef TEACHOS_X86_64_MEMORY_ADDRESS_HPP +#define TEACHOS_X86_64_MEMORY_ADDRESS_HPP + +#include +#include +#include +#include + +namespace teachos::x86_64::memory +{ + + enum struct address_type : bool + { + linear, + physical, + }; + + template + struct address + { + constexpr explicit address(std::uintptr_t value) noexcept + : m_value{value} + { + } + + explicit address(std::byte * pointer) noexcept + : m_value{std::bit_cast(pointer)} + { + } + + explicit operator std::byte *() const noexcept { return std::bit_cast(m_value); } + + auto constexpr operator<=>(address const &) const noexcept -> std::strong_ordering = default; + auto constexpr operator==(address const &) const noexcept -> bool = default; + + auto constexpr raw() const noexcept -> std::uintptr_t { return m_value; } + + private: + std::uintptr_t m_value{}; + }; + + using linear_address = address; + using physical_address = address; + +} // namespace teachos::x86_64::memory + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/frame.hpp b/arch/x86_64/include/x86_64/memory/frame.hpp new file mode 100644 index 0000000..21565fd --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/frame.hpp @@ -0,0 +1,95 @@ +#ifndef TEACHOS_X86_64_MEMORY_FRAME_HPP +#define TEACHOS_X86_64_MEMORY_FRAME_HPP + +#include "x86_64/memory/address.hpp" + +#include +#include + +namespace teachos::x86_64::memory +{ + /** + * @brief Specific physical frame containing helper functions to determine if a specific address is in that + * physical frame or not. + */ + struct frame + { + auto static inline constexpr DEFAULT_SIZE = std::size_t{4096}; ///< Default page size of x86_84 is always 4KiB. + + /** + * @brief Defaulted constructor. + */ + constexpr frame() = default; + + /** + * @brief Constructor. + * + * @param frame_number Index number that should be assigned to this physical frame. + */ + explicit constexpr frame(std::size_t number) + : m_number(number) + { + } + + /** + * @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 constexpr static containing(physical_address address) noexcept -> frame + { + return frame{address.raw() / DEFAULT_SIZE}; + } + + /** + * @brief Get the start address of this physical frame. + * + * @return Start address of the physical frame. + */ + auto constexpr start_address() const noexcept -> physical_address + { + return physical_address{m_number * DEFAULT_SIZE}; + } + + auto constexpr operator+(std::size_t offset) const noexcept -> frame { return frame{m_number + offset}; } + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying frame number. + */ + auto constexpr operator++(int) noexcept -> frame + { + auto copy = *this; + return ++copy; + } + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying frame number. + */ + auto constexpr operator++() noexcept -> frame & + { + ++m_number; + return *this; + } + + /** + * @brief Defaulted equals operator. + */ + auto constexpr operator==(frame const & other) const noexcept -> bool = default; + + /** + * @brief Defaulted three-way comparison operator. + */ + auto constexpr operator<=>(frame const & other) const noexcept -> std::strong_ordering = default; + + private: + std::size_t m_number{}; ///< Index number of the current physical frame, used to distinguish it from other frames. + }; + +} // namespace teachos::x86_64::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_frame_HPP 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..23bea10 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -0,0 +1,76 @@ +#ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP +#define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP + +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/frame.hpp" + +#include + +#include +#include + +namespace teachos::x86_64::memory +{ + /** + * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any + * deallocated frames. + */ + struct region_allocator + { + struct memory_information + { + std::pair image_range; + std::pair mbi_range; + multiboot2::memory_map memory_map; + }; + + /** + * @brief Constructor. + * + * @param mem_info Structure containing all relevant information to map and allocate memory. + */ + explicit region_allocator(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; + + /** + * @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 allocated in the first place. + * + * @param physical_frame Previously allocated physical_frame that should be deallocated. + */ + auto deallocate_frame(frame const & physical_frame) -> void; + + private: + /** + * @brief Find the next memory area and write it into current_area. + */ + auto choose_next_area() -> void; + + frame m_next_frame; ///< The physical_frame after the last allocated one. + std::optional m_current_region; ///< The memory region currently allocated from + multiboot2::memory_map m_memory_map; ///< The boot loader supplied memory map. + frame const m_kernel_start; ///< The start address of the kernel code in memory. + frame const m_kernel_end; ///< The end address of the kernel code in memory. + frame const m_multiboot_start; ///< The start address of the multiboot code in memory. + frame const m_multiboot_end; ///< The end address of the multiboot code in memory. + }; + +} // namespace teachos::x86_64::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/scripts/x86-64-linker-script.txt b/arch/x86_64/scripts/x86-64-linker-script.txt new file mode 100644 index 0000000..3d9a7ae --- /dev/null +++ b/arch/x86_64/scripts/x86-64-linker-script.txt @@ -0,0 +1,150 @@ +ENTRY(_start) + +/***************************************************************************** + * Virtual and linear start addresses of the TeachOS kernel + *****************************************************************************/ +TEACHOS_LOW = 1M; + +PHDRS { + boot_rodata PT_LOAD FLAGS(4); + boot_text PT_LOAD FLAGS(5); + boot_data PT_LOAD FLAGS(6); + + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(6); + rodata PT_LOAD FLAGS(4); +} + +SECTIONS +{ + /*************************************************************************** + * Load the bootstrap code into low memory. We need to be accessible in + * 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; + + /*************************************************************************** + * We want to be able to be able to access all memory (linear and virtual) + * during bootstrapping and operation. To achieve this, we define some + * symbols at the beginning. + ***************************************************************************/ + _start_linear = .; + _start_virtual = .; + + /*************************************************************************** + * The bootstrapping infratructure goes first. We first place the read-only + * data, followed by our code, initialized mutable data, and finally our + * uninitialized mutable data. + ***************************************************************************/ + .boot_rodata ALIGN(4K) : AT(ADDR (.boot_rodata)) + { + KEEP(*(.boot_mbh)) + *(.boot_rodata) + } :boot_rodata + + .boot_text ALIGN(4K) : AT(ADDR (.boot_text)) + { + *(.boot_text) + } :boot_text + + .boot_bss ALIGN(4K) : AT(ADDR (.boot_bss)) + { + *(.boot_bss) + *(.boot_stack) + } + + .boot_data ALIGN(4K) : AT(ADDR (.boot_data)) + { + *(.boot_data) + } :boot_data + + /*************************************************************************** + * 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)) + } + + .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) + { + *(.stl_text .stl_text*) + KEEP(*libstdc++.a:*(.text .text.*)) + } + + .text ALIGN(4K) : AT(ADDR (.text)) + { + *(.text .text.*) + } + + .user_text ALIGN(4K) : AT(ADDR (.user_text)) + { + *(.user_text .user_text.*) + } + + .rodata ALIGN(4K) : AT (ADDR (.rodata)) + { + *(.rodata) + *(.rodata.*) + } :rodata + + .ctors ALIGN(4K) : AT (ADDR (.ctors)) + { + KEEP(*crtbegin.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*crtend.o(.ctors)) + } :data + + .dtors ALIGN(4K) : AT (ADDR (.dtors)) + { + KEEP(*crtbegin.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*crtend.o(.dtors)) + } + + .bss ALIGN(4K) : AT (ADDR (.bss)) + { + *(COMMON) + *(.bss*) + } + + .data ALIGN(4K) : AT (ADDR (.data)) + { + *(.data*) + } + + .user_data ALIGN(4K) : AT (ADDR (.user_data)) + { + *(.user_data .user_data.*) + } + + /*************************************************************************** + * 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; + + /DISCARD/ : { *(.comment) } +} diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index ada6426..e0cff7c 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -12,7 +12,7 @@ * Reserve some space for the Multiboot 2 information pointer. */ .global multiboot_information_pointer -multiboot_information_pointer: .skip 4 +multiboot_information_pointer: .skip 8 /** * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 245d7bd..2b16beb 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -1,62 +1,54 @@ #include "arch/memory.hpp" -// #include "noarch/error.hpp" -// #include "noarch/print.hpp" -// #include "x86_64/bootstrap/mutiboot.hpp" -// #include "x86_64/memory/frame_allocator.hpp" -// #include "x86_64/memory/mbi_frame_allocator.hpp" +#include "kern/error.hpp" -// #include -// #include -// #include -// #include +#include "arch/asm_pointer.hpp" +#include "x86_64/memory/region_allocator.hpp" -namespace teachos::arch::memory -{ +#include - // namespace - // { - // /** - // * @brief Remap the kernel according to the ELF information. - // * - // * After initial bootup, a basic identity mapping of the lower 1GiB is set up. This mapping allows execution - // from, - // * as well as read and write access to, the mapped memory. In order to protect the kernel, remap it according to - // the - // * information supplied by the ELF file. This means remapping code sections as read-only and data sections as - // * no-execute (and read only for .rodata). - // * - // * @param sections Information about the sections in the loaded kernel binary. - // * @param allocator The frame allocator used to create new page mappings. - // */ - // auto remap_kernel(elf::section_header_table const & sections, x86_64::memory::frame_allocator & allocator) -> - // void - // { - // static_cast(sections); - // static_cast(allocator); - // } - // } // namespace +#include - auto init() -> void - { - // kernel::println("Initializing memory"); +extern "C" teachos::arch::asm_pointer multiboot_information_pointer; - // if (!x86_64::bootstrap::multiboot_information_pointer->has()) - // { - // kernel::panic("Received no memory map from the boot loader!"); - // } +namespace teachos::arch::memory +{ + namespace + { + auto constinit is_initialized = std::atomic_flag{}; - // if (!x86_64::bootstrap::multiboot_information_pointer->has()) - // { - // kernel::panic("Received no ELF symbol information from the boot loader!"); - // } + // auto create_memory_information() -> x86_64::memory::region_allocator::memory_information { - // auto memory_map = x86_64::bootstrap::multiboot_information_pointer->memory_map(); - // auto elf_symbols = x86_64::bootstrap::multiboot_information_pointer->elf_symbols(); - // auto section_header_table = elf::section_header_table{elf_symbols.data(), elf::file_class::bits_64}; - // auto allocator = x86_64::memory::mbi_frame_allocator{memory_map, section_header_table}; + // }; + } // namespace - // remap_kernel(section_header_table, allocator); + auto init() -> void + { + if (is_initialized.test_and_set()) + { + teachos::panic("[x86_64] Memory management has already been initialized."); + } + + auto memory_map = multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + teachos::panic("[x86_64] No memory map available."); + } + + // auto mem_info = x86_64::memory::region_allocator::memory_information{}; + // auto allocator = x86_64::memory::region_allocator{mem_info}; + + // 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/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/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp new file mode 100644 index 0000000..c9a98b4 --- /dev/null +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -0,0 +1,95 @@ +// #include "arch/memory/allocator/region_allocator.hpp" + +// #include "arch/exception_handling/assert.hpp" + +// #include +// #include +// #include + +#include "x86_64/memory/region_allocator.hpp" + +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/frame.hpp" + +#include + +#include +#include + +namespace teachos::x86_64::memory +{ + namespace + { + auto constexpr last_frame(multiboot2::memory_map::region const & region) + { + return frame::containing(physical_address{region.base + region.size_in_B - 1}); + } + } // namespace + + region_allocator::region_allocator(memory_information const & mem_info) + : m_next_frame{} + , m_current_region{} + , m_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) { return last_frame(region) >= next; }); + + auto lowest_region_with_free_frames = + std::ranges::min_element(next_area_with_free_frames, [](auto lhs, auto rhs) { 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_frame() -> std::optional + { + 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 (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + { + m_next_frame = m_kernel_end + 1; + } + else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + { + m_next_frame = m_multiboot_end + 1; + } + else + { + auto allocated = m_next_frame; + ++m_next_frame; + return allocated; + } + + return allocate_frame(); + } + + auto region_allocator::deallocate_frame(frame const &) -> void {} +} // namespace teachos::x86_64::memory diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index 367e8cb..a5f2e14 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -99,17 +99,17 @@ namespace multiboot2::impl /** * @brief Start address of this region */ - std::uint64_t const base; + std::uint64_t base; /** * @brief Size of this region in bytes. */ - std::uint64_t const size_in_B; + std::uint64_t size_in_B; /** * @brief Type of this region. */ - memory_type const type; + memory_type type; std::uint32_t : 0; }; diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index b84ef2c..e82326d 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -40,7 +40,10 @@ namespace multiboot2::impl { m_current = next; } - m_current.reset(); + else + { + m_current.reset(); + } } return *this; } -- cgit v1.2.3 From 4ae38294b0db1870f82cc402dc4a8bb38cea4a67 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:16:43 +0000 Subject: x86_64: don't lose multi boot information pointer Since the transition to a PIE, more registers are required to perform the relative lookups of data references. As part of that change, a subtle mistake was introduced in _start, overwriting the multiboot information pointer that gets handed to kernel by the boot loader in %ebx. --- arch/x86_64/src/boot/boot.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index e0cff7c..ba5c6f0 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -195,9 +195,9 @@ _start: call .Lstart_get_ip .Lstart_get_ip: pop %esi - lea (stack_top - .Lstart_get_ip)(%esi), %ebx + lea (stack_top - .Lstart_get_ip)(%esi), %ecx - mov %ebx, %esp + mov %ecx, %esp mov %esp, %ebp call assert_loaded_by_multiboot2_loader -- cgit v1.2.3 From fd6282947bb13af4cfff8cf2209c442b568275f3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:35:58 +0000 Subject: x86_64: add data segment to boot GDT --- arch/x86_64/src/boot/boot.s | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index ba5c6f0..2decf26 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -58,19 +58,22 @@ stack_top: .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. + * A valid Global Descriptor Table is still required in long mode. * + * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). * 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: +global_descriptor_table_null = . - global_descriptor_table +.quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +global_descriptor_table_data = . - global_descriptor_table +.quad (1<<41) | (1<<44) | (1<<47) global_descriptor_table_end: /** @@ -402,7 +405,7 @@ prepare_page_maps: .code64 _transition_to_long_mode: - xor %rax, %rax + mov $global_descriptor_table_data, %rax mov %rax, %ss mov %rax, %ds mov %rax, %es -- cgit v1.2.3 From 3a67a3e1088508148002e7c20befa571fb0b72c0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:44:15 +0000 Subject: x86_64: set GDT entries as accessed. --- arch/x86_64/src/boot/boot.s | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 2decf26..f3d9585 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -60,6 +60,7 @@ stack_top: /** * A valid Global Descriptor Table is still required in long mode. * + * Bit 41: "A" in the access byte => mark the segment as accessed. * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). * 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. @@ -71,9 +72,9 @@ global_descriptor_table: global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1<<40) | (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) global_descriptor_table_data = . - global_descriptor_table -.quad (1<<41) | (1<<44) | (1<<47) +.quad (1<<40) | (1<<41) | (1<<44) | (1<<47) global_descriptor_table_end: /** -- cgit v1.2.3 From 2e58f85807427d121fe1de80089e602f1f35944b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 20:25:14 +0200 Subject: docs: introduce technical briefs Also removes arch and cross inclusion for now, since the architecture is undergoing major rework. --- docs/arch.rst | 9 -- docs/briefs.rst | 9 ++ docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst | 161 ++++++++++++++++++++++ docs/conf.py | 6 +- docs/cross.rst | 9 -- docs/index.rst | 3 +- docs/requirements.txt | 3 + 7 files changed, 177 insertions(+), 23 deletions(-) delete mode 100644 docs/arch.rst create mode 100644 docs/briefs.rst create mode 100644 docs/briefs/tb0001-pic-in-32-bit-x86-assembly.rst delete mode 100644 docs/cross.rst create mode 100644 docs/requirements.txt 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/conf.py b/docs/conf.py index 90ed3dc..067c1cf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ 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 = [] @@ -21,8 +21,8 @@ exclude_patterns = [] # -- 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/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..3c3a2e5 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +Sphinx~=8.2.0 +breathe~=4.36.0 +sphinx_book_theme~=1.1.0 -- cgit v1.2.3 From eb22cdcad4c27527a63a6e457e80c752f76821c6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 21 Jul 2025 12:13:10 +0000 Subject: x86_64: clean up bootstrap code --- .vscode/settings.json | 4 + arch/x86_64/src/boot/boot.s | 512 +++++++++++++++++++++++--------------------- 2 files changed, 269 insertions(+), 247 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e8e872e..0d62c95 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,5 +14,9 @@ "[cpp]": { "editor.formatOnSave": true, "editor.tabSize": 2, + }, + + "[gas]": { + "editor.rulers": [80] } } \ No newline at end of file diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index f3d9585..7a46795 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -1,50 +1,22 @@ -.extern _end_physical -.extern _init -.extern kernel_main - - /** - * Uninitialized data for the bootstrapping process. + * @brief Uninitialized data for the bootstrapping process. */ .section .boot_bss, "aw", @nobits /** - * Reserve some space for the Multiboot 2 information pointer. + * @brief Storage for the multiboot2 information pointer. */ .global multiboot_information_pointer multiboot_information_pointer: .skip 8 -/** - * 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. + * @brief Storage for the bootstrap stack. */ .section .boot_stack, "aw", @nobits .align 16 @@ -53,210 +25,240 @@ stack_bottom: .skip 1 << 20 stack_top: /** - * Constants for the bootstrapping process. + * @brief Constants for the bootstrapping process. */ .section .boot_rodata, "a", @progbits /** - * A valid Global Descriptor Table is still required in long mode. - * - * Bit 41: "A" in the access byte => mark the segment as accessed. - * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). - * 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 + * @brief A basic GDT for long mode. */ - global_descriptor_table: +.set GDT_ACCESSED, 40 +.set GDT_READ_WRITE, 41 +.set GDT_EXECUTABLE, 43 +.set GDT_DESCRIPTOR_TYPE, 44 +.set GDT_PRESENT, 47 +.set GDT_LONG_MODE, 53 global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<40) | (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_EXECUTABLE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) | (1 << GDT_LONG_MODE) global_descriptor_table_data = . - global_descriptor_table -.quad (1<<40) | (1<<41) | (1<<44) | (1<<47) +.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) global_descriptor_table_end: -/** - * 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." +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." /** - * Mutable data for the bootstrapping process. + * @brief Initialized data for the bootstrapping process. */ .section .boot_data, "aw", @progbits /** - * We need a pointer to our current position in the VGA text buffer. + * @brief A pointer to the current position within the VGA text buffer. */ .global vga_buffer_pointer vga_buffer_pointer: .quad 0xb8000 /** - * Code for the bootstrapping process. + * @brief Code for the bootstrapping process. */ .section .boot_text, "ax", @progbits .align 16 .code32 -.global halt -halt: -1: - hlt - jmp 1b +.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 /** - * Print a given panic message and then halt the machine. + * @brief Prepare the environment and start the kernel. * - * Parameters: - * - [stack - 0] message: the message to print + * 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. */ -_panic: - push %ebp +.global _start +_start: + call 0f +0: + pop %esi + + lea (stack_top - 0b)(%esi), %ecx + + mov %ecx, %esp mov %esp, %ebp - call .Lpanic_get_ip -.Lpanic_get_ip: - pop %eax - lea (message_prefix_panic - .Lpanic_get_ip)(%eax), %eax + call _assert_loaded_by_multiboot2_loader + call _save_multiboot_information_pointer - push %eax - push $0x4f - call _print - add $8, %esp + call _assert_cpuid_instruction_is_supported + call _assert_cpu_supports_long_mode - push 8(%ebp) - push 0x4f - call _print - add $8, %esp + call _prepare_page_maps + call _enable_paging + call _enable_sse + call _reload_gdt + + lea (_transition_to_long_mode - 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. + */ +.global halt +_halt: + function_start - call halt +1: + hlt + jmp 1b + + function_end /** - * Print a message via the VGA buffer. + * @brief Print a message via the VGA text buffer. * - * Parameters: - * - [stack - 4] message: the message to print - * - [stack - 0] color: the color of the message + * @param ebp+12 The message to print. + * @param ebp+8 The color to print the message in. */ _print: - push %ebp - mov %esp, %ebp + pie_function_start - push %ebx - push %esi push %edi + push %ebx - call .Lprint_get_ip -.Lprint_get_ip: - pop %edi - lea (vga_buffer_pointer - .Lprint_get_ip)(%edi), %edi - - mov 8(%ebp), %eax - mov 12(%ebp), %ebx + mov 8(%ebp), %al + mov 12(%ebp), %edx mov $0, %ecx - mov (%edi), %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) + 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 .Lprint_loop + jmp 1b -.Lupdate_vga_buffer_address: +2: shl $1, %ecx - add %ecx, %esi - mov %esi, (%edi) + add %ecx, %edi + lea (vga_buffer_pointer - 0b)(%esi), %ecx + mov %edi, (%ecx) -.Lprint_end: - pop %edi - pop %esi pop %ebx - mov %ebp, %esp - pop %ebp - ret + pop %edi + + pie_function_end /** - * This is our entry point after being loaded by the bootloader. + * @brief Print a given panic message and then halt the machine as if by calling ::halt() * - * Having this in assembly makes it easier for us to keep things together. + * @param ebp+4 A message to print. + * @return This function does not return. */ -.global _start -_start: - call .Lstart_get_ip -.Lstart_get_ip: - pop %esi - lea (stack_top - .Lstart_get_ip)(%esi), %ecx - - mov %ecx, %esp - mov %esp, %ebp +_panic: + pie_function_start - 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 + lea (message_prefix_panic - 0b)(%esi), %eax - sub $10, %esp - lea (global_descriptor_table - .Lstart_get_ip)(%esi), %eax - movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) - mov %eax, 2(%esp) - movl $0, 6(%esp) + push %eax + push $0x4f + call _print - lgdt (%esp) - add $10, %esp + mov 16(%ebp), %eax + mov %eax, 8(%ebp) + call _print + add $8, %esp - lea (_transition_to_long_mode - .Lstart_get_ip)(%esi), %eax - pushl $global_descriptor_table_code - pushl %eax - lret + call _halt - call halt + pie_function_end /** - * Assert that the CPU supports going into long mode. + * 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_cpu_supports_long_mode: - mov $0x80000000, %eax - cpuid - cmp $0x80000001, %eax - jb .Llong_mode_assertion_failed +_assert_loaded_by_multiboot2_loader: + pie_function_start - mov $0x80000001, %eax - cpuid - test $(1 << 29), %edx - jz .Llong_mode_assertion_failed - ret -.Llong_mode_assertion_failed: - call .Lassert_cpu_supports_long_mode_fail_get_ip -.Lassert_cpu_supports_long_mode_fail_get_ip: - pop %eax - lea (mesage_long_mode_not_supported - .Lassert_cpu_supports_long_mode_fail_get_ip)(%eax), %eax + .set MULTIBOOT2_MAGIC, 0x36d76289 + cmp $MULTIBOOT2_MAGIC, %eax + je 1f + lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax push %eax call _panic +1: + pie_function_end /** - * Assert that the CPU supports the CPUID instruction. + * @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: +_assert_cpuid_instruction_is_supported: + pie_function_start + pushfl pop %eax mov %eax, %ecx @@ -271,52 +273,100 @@ assert_cpuid_instruction_is_supported: popfl cmp %ecx, %eax - je .Lcpuid_assertion_fail - ret -.Lcpuid_assertion_fail: - call .Lassert_cpuid_instruction_is_supported_fail_get_ip -.Lassert_cpuid_instruction_is_supported_fail_get_ip: - pop %eax - lea (message_cpuid_instruction_no_supported - .Lassert_cpuid_instruction_is_supported_fail_get_ip)(%eax), %eax + jne 1f + lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax push %eax call _panic +1: + 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`. + * @brief Assert that the CPU supports going into long mode. */ -assert_loaded_by_multiboot2_loader: - cmp $0x36d76289, %eax /* Check if we received the - expected magic */ - jne .Lmultiboot2_assertion_fail /* Panic otherwise */ - call .Lassert_loaded_by_multiboot2_loader_get_ip -.Lassert_loaded_by_multiboot2_loader_get_ip: - pop %eax - lea (multiboot_information_pointer - .Lassert_loaded_by_multiboot2_loader_get_ip)(%eax), %eax - mov %ebx, (%eax) /* Store the MBI pointer */ - ret -.Lmultiboot2_assertion_fail: - call .Lassert_loaded_by_multiboot2_loader_fail_get_ip -.Lassert_loaded_by_multiboot2_loader_fail_get_ip: - pop %eax - lea (message_not_loaded_by_multiboot2 - .Lassert_loaded_by_multiboot2_loader_fail_get_ip)(%eax), %eax +_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 /** - * Enable paging. + * @brief Prepare a recursive page map hierarchy + * + * 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. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + .set HUGE_PAGES_TO_MAP, 16 + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + 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. - */ -enable_paging: - call .Lenable_paging_get_ip -.Lenable_paging_get_ip: - pop %eax -lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax + * + * @return void + */For +_enable_paging: + pie_function_start + + lea (page_map_level_4 - 0b)(%esi), %eax mov %eax, %cr3 /* Enable Physical Address Extension */ @@ -335,12 +385,14 @@ lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax or $(1 << 31), %eax mov %eax, %cr0 - ret + pie_function_end /** - * Enable use of SSE instructions. + * @brief Enable use of SSE instructions. */ -enable_sse: +_enable_sse: + function_start + mov %cr0, %eax and $0xfffffffb, %eax or $0x00000002, %eax @@ -350,57 +402,26 @@ enable_sse: or $(3 << 9), %eax mov %eax, %cr4 - ret + function_end /** - * Prepare the page maps. + * @brief Prepare a new GTD and load make it active. * - * 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. + * @return void */ -prepare_page_maps: - call .Lprepare_page_maps_get_ip -.Lprepare_page_maps_get_ip: - pop %edi - /* Map the P4 table recursively */ - lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %eax - mov %eax, %ebx - or $0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (511 * 8)(%ebx) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %eax - lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %ebx - or $0x3, %eax - mov %eax, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%ebx) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %eax - lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %ebx - or $0x3, %eax - mov %eax, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%ebx) - - xor %ecx, %ecx - - push %esi - lea (_end_linear - .Lprepare_page_maps_get_ip)(%edi), %esi - shr $21, %esi - add $2, %esi +_reload_gdt: + pie_function_start -.Lmap_pages: - lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %ebx - mov $(1 << 21), %eax - mul %ecx - or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, (%ebx,%ecx,8) + 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) - inc %ecx - cmp %esi, %ecx - jne .Lmap_pages + lgdt (%esp) + add $10, %esp - pop %esi - ret + pie_function_end .section .boot_text, "ax", @progbits .code64 @@ -413,12 +434,9 @@ _transition_to_long_mode: mov %rax, %fs mov %rax, %gs - leaq vga_buffer_pointer(%rip), %rax - movl $0xb8000, (%rax) - xor %rax, %rax call _init call main - call halt + call _halt -- cgit v1.2.3 From ce8683e63fc9ef59e1800927afb1753507a42ef6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 22 Jul 2025 20:48:11 +0000 Subject: x86_64: extract constants from bootstrap code --- arch/x86_64/CMakeLists.txt | 2 +- arch/x86_64/include/x86_64/boot/boot.hpp | 66 +++++ arch/x86_64/src/boot/boot.S | 433 ++++++++++++++++++++++++++++++ arch/x86_64/src/boot/boot.s | 442 ------------------------------- arch/x86_64/src/memory.cpp | 5 +- 5 files changed, 502 insertions(+), 446 deletions(-) create mode 100644 arch/x86_64/include/x86_64/boot/boot.hpp create mode 100644 arch/x86_64/src/boot/boot.S delete mode 100644 arch/x86_64/src/boot/boot.s diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index d1af777..a32a0f5 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -34,7 +34,7 @@ target_sources("arch-x86_64" PRIVATE #]============================================================================] target_sources("arch-x86_64" PRIVATE - "src/boot/boot.s" + "src/boot/boot.S" "src/boot/crti.s" "src/boot/crtn.s" "src/boot/multiboot.s" 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..066e49e --- /dev/null +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -0,0 +1,66 @@ +#ifndef TEACHOS_X86_64_BOOT_BOOT_H +#define TEACHOS_X86_64_BOOT_BOOT_H + +#ifdef __ASSEMBLER__ +/** + * @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) + +#else + +#include "arch/asm_pointer.hpp" + +#include + +extern "C" +{ + /** + * @brief A pointer to the multiboot 2 information structure provided by the boot loader. + */ + extern teachos::arch::asm_pointer multiboot_information_pointer; + + /** + * @brief A pointer to the VGA text mode buffer. + */ + extern teachos::arch::asm_pointer> vga_buffer_pointer; +} + +#endif + +#endif diff --git a/arch/x86_64/src/boot/boot.S b/arch/x86_64/src/boot/boot.S new file mode 100644 index 0000000..d65c865 --- /dev/null +++ b/arch/x86_64/src/boot/boot.S @@ -0,0 +1,433 @@ +#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_map_level_4: .skip 512 * 8 +page_map_level_3: .skip 512 * 8 +page_map_level_2: .skip 512 * 8 + +/** + * @brief Storage for the bootstrap stack. + */ +.section .boot_stack, "aw", @nobits +.align 16 + +stack_bottom: .skip 1 << 20 +stack_top: + +/** + * @brief Constants for the bootstrapping process. + */ +.section .boot_rodata, "a", @progbits + +/** + * @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_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE +global_descriptor_table_data = . - global_descriptor_table +.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT +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. + */ +_start: + call 0f +0: + pop %esi + + lea (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 + + call _prepare_page_maps + call _enable_paging + call _enable_sse + call _reload_gdt + + lea (_transition_to_long_mode - 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 + * + * 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. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + 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 + +.section .boot_text, "ax", @progbits +.code64 + +_transition_to_long_mode: + mov $global_descriptor_table_data, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + + xor %rax, %rax + + call _init + + call main + call _halt diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s deleted file mode 100644 index 7a46795..0000000 --- a/arch/x86_64/src/boot/boot.s +++ /dev/null @@ -1,442 +0,0 @@ -/** - * @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_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 - -/** - * @brief Storage for the bootstrap stack. - */ -.section .boot_stack, "aw", @nobits -.align 16 - -stack_bottom: .skip 1 << 20 -stack_top: - -/** - * @brief Constants for the bootstrapping process. - */ -.section .boot_rodata, "a", @progbits - -/** - * @brief A basic GDT for long mode. - */ -global_descriptor_table: -.set GDT_ACCESSED, 40 -.set GDT_READ_WRITE, 41 -.set GDT_EXECUTABLE, 43 -.set GDT_DESCRIPTOR_TYPE, 44 -.set GDT_PRESENT, 47 -.set GDT_LONG_MODE, 53 -global_descriptor_table_null = . - global_descriptor_table -.quad 0 -global_descriptor_table_code = . - global_descriptor_table -.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_EXECUTABLE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) | (1 << GDT_LONG_MODE) -global_descriptor_table_data = . - global_descriptor_table -.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) -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 (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 - - call _prepare_page_maps - call _enable_paging - call _enable_sse - call _reload_gdt - - lea (_transition_to_long_mode - 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. - */ -.global halt -_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 - - .set MULTIBOOT2_MAGIC, 0x36d76289 - 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 - * - * 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. - * - * @return void - */ -_prepare_page_maps: - pie_function_start - push %ebx - - .set HUGE_PAGES_TO_MAP, 16 - - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ - push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx - -1: - mov $(1 << 21), %eax - mul %ecx - or $0b10000011, %eax - mov %eax, (%ebx, %ecx, 8) - - inc %ecx - cmp %edi, %ecx - jne 1b - - pop %edi - pop %ebx - 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 - */For -_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 - -.section .boot_text, "ax", @progbits -.code64 - -_transition_to_long_mode: - mov $global_descriptor_table_data, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - - xor %rax, %rax - - call _init - - call main - call _halt diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 2b16beb..a31627b 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -2,14 +2,13 @@ #include "kern/error.hpp" -#include "arch/asm_pointer.hpp" -#include "x86_64/memory/region_allocator.hpp" +#include "x86_64/boot/boot.hpp" #include #include -extern "C" teachos::arch::asm_pointer multiboot_information_pointer; +// extern "C" teachos::arch::asm_pointer multiboot_information_pointer; namespace teachos::arch::memory { -- cgit v1.2.3 From c8cb4346064c69ab8431aa0d3c287e2fad60ce80 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 22 Jul 2025 21:23:23 +0000 Subject: x86_64: split bootstrap code along mode lines --- arch/x86_64/CMakeLists.txt | 3 +- arch/x86_64/src/boot/boot.S | 433 ----------------------------------------- arch/x86_64/src/boot/boot32.S | 418 +++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/boot/entry64.s | 21 ++ 4 files changed, 441 insertions(+), 434 deletions(-) delete mode 100644 arch/x86_64/src/boot/boot.S create mode 100644 arch/x86_64/src/boot/boot32.S create mode 100644 arch/x86_64/src/boot/entry64.s diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index a32a0f5..6bb9e53 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -34,9 +34,10 @@ target_sources("arch-x86_64" PRIVATE #]============================================================================] target_sources("arch-x86_64" PRIVATE - "src/boot/boot.S" + "src/boot/boot32.S" "src/boot/crti.s" "src/boot/crtn.s" + "src/boot/entry64.s" "src/boot/multiboot.s" ) diff --git a/arch/x86_64/src/boot/boot.S b/arch/x86_64/src/boot/boot.S deleted file mode 100644 index d65c865..0000000 --- a/arch/x86_64/src/boot/boot.S +++ /dev/null @@ -1,433 +0,0 @@ -#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_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 - -/** - * @brief Storage for the bootstrap stack. - */ -.section .boot_stack, "aw", @nobits -.align 16 - -stack_bottom: .skip 1 << 20 -stack_top: - -/** - * @brief Constants for the bootstrapping process. - */ -.section .boot_rodata, "a", @progbits - -/** - * @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_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE -global_descriptor_table_data = . - global_descriptor_table -.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT -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. - */ -_start: - call 0f -0: - pop %esi - - lea (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 - - call _prepare_page_maps - call _enable_paging - call _enable_sse - call _reload_gdt - - lea (_transition_to_long_mode - 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 - * - * 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. - * - * @return void - */ -_prepare_page_maps: - pie_function_start - push %ebx - - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ - push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx - -1: - mov $(1 << 21), %eax - mul %ecx - or $0b10000011, %eax - mov %eax, (%ebx, %ecx, 8) - - inc %ecx - cmp %edi, %ecx - jne 1b - - pop %edi - pop %ebx - 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 - -.section .boot_text, "ax", @progbits -.code64 - -_transition_to_long_mode: - mov $global_descriptor_table_data, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - - xor %rax, %rax - - call _init - - call 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..7e6c2ae --- /dev/null +++ b/arch/x86_64/src/boot/boot32.S @@ -0,0 +1,418 @@ +#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_map_level_4: .skip 512 * 8 +page_map_level_3: .skip 512 * 8 +page_map_level_2: .skip 512 * 8 + +/** + * @brief Storage for the bootstrap stack. + */ +.section .boot_stack, "aw", @nobits +.align 16 + +stack_bottom: .skip 1 << 20 +stack_top: + +/** + * @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_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE +global_descriptor_table_data = . - global_descriptor_table +.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT +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 (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 + + call _prepare_page_maps + 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 + * + * 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. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + 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/entry64.s b/arch/x86_64/src/boot/entry64.s new file mode 100644 index 0000000..f575c50 --- /dev/null +++ b/arch/x86_64/src/boot/entry64.s @@ -0,0 +1,21 @@ +.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 + + xor %rax, %rax + + call _init + + call main + +1: + hlt + jmp 1b -- cgit v1.2.3 From 24a9f628656188d0e6ec4a7537ee758c1a88a847 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 22 Jul 2025 22:02:22 +0000 Subject: docs: import first draft of tb0002 --- docs/briefs/tb0002-x86_64_bootstrap.rst | 154 ++++++++++++++++++++++++++++++++ docs/requirements.txt | 1 - 2 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 docs/briefs/tb0002-x86_64_bootstrap.rst 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 `_. + +.. [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 `_. + +.. [3] AMD, Inc., *AMD64 Architecture Programmer’s Manual, Volume 3: General-Purpose and System Instructions*, Publication No. 24594, Rev. 3.42, June 2025. `Online `_. diff --git a/docs/requirements.txt b/docs/requirements.txt index 3c3a2e5..733e873 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,2 @@ Sphinx~=8.2.0 -breathe~=4.36.0 sphinx_book_theme~=1.1.0 -- cgit v1.2.3 From b4c45759c94d61493bbb88dacfd5c1bccfb13ac6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 07:26:45 +0000 Subject: x86_64: remove stray copy of ld script --- arch/x86_64/scripts/x86-64-linker-script.txt | 150 --------------------------- 1 file changed, 150 deletions(-) delete mode 100644 arch/x86_64/scripts/x86-64-linker-script.txt diff --git a/arch/x86_64/scripts/x86-64-linker-script.txt b/arch/x86_64/scripts/x86-64-linker-script.txt deleted file mode 100644 index 3d9a7ae..0000000 --- a/arch/x86_64/scripts/x86-64-linker-script.txt +++ /dev/null @@ -1,150 +0,0 @@ -ENTRY(_start) - -/***************************************************************************** - * Virtual and linear start addresses of the TeachOS kernel - *****************************************************************************/ -TEACHOS_LOW = 1M; - -PHDRS { - boot_rodata PT_LOAD FLAGS(4); - boot_text PT_LOAD FLAGS(5); - boot_data PT_LOAD FLAGS(6); - - text PT_LOAD FLAGS(5); - data PT_LOAD FLAGS(6); - rodata PT_LOAD FLAGS(4); -} - -SECTIONS -{ - /*************************************************************************** - * Load the bootstrap code into low memory. We need to be accessible in - * 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; - - /*************************************************************************** - * We want to be able to be able to access all memory (linear and virtual) - * during bootstrapping and operation. To achieve this, we define some - * symbols at the beginning. - ***************************************************************************/ - _start_linear = .; - _start_virtual = .; - - /*************************************************************************** - * The bootstrapping infratructure goes first. We first place the read-only - * data, followed by our code, initialized mutable data, and finally our - * uninitialized mutable data. - ***************************************************************************/ - .boot_rodata ALIGN(4K) : AT(ADDR (.boot_rodata)) - { - KEEP(*(.boot_mbh)) - *(.boot_rodata) - } :boot_rodata - - .boot_text ALIGN(4K) : AT(ADDR (.boot_text)) - { - *(.boot_text) - } :boot_text - - .boot_bss ALIGN(4K) : AT(ADDR (.boot_bss)) - { - *(.boot_bss) - *(.boot_stack) - } - - .boot_data ALIGN(4K) : AT(ADDR (.boot_data)) - { - *(.boot_data) - } :boot_data - - /*************************************************************************** - * 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)) - } - - .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) - { - *(.stl_text .stl_text*) - KEEP(*libstdc++.a:*(.text .text.*)) - } - - .text ALIGN(4K) : AT(ADDR (.text)) - { - *(.text .text.*) - } - - .user_text ALIGN(4K) : AT(ADDR (.user_text)) - { - *(.user_text .user_text.*) - } - - .rodata ALIGN(4K) : AT (ADDR (.rodata)) - { - *(.rodata) - *(.rodata.*) - } :rodata - - .ctors ALIGN(4K) : AT (ADDR (.ctors)) - { - KEEP(*crtbegin.o(.ctors)) - KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP(*(SORT(.ctors.*))) - KEEP(*crtend.o(.ctors)) - } :data - - .dtors ALIGN(4K) : AT (ADDR (.dtors)) - { - KEEP(*crtbegin.o(.dtors)) - KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP(*(SORT(.dtors.*))) - KEEP(*crtend.o(.dtors)) - } - - .bss ALIGN(4K) : AT (ADDR (.bss)) - { - *(COMMON) - *(.bss*) - } - - .data ALIGN(4K) : AT (ADDR (.data)) - { - *(.data*) - } - - .user_data ALIGN(4K) : AT (ADDR (.user_data)) - { - *(.user_data .user_data.*) - } - - /*************************************************************************** - * 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; - - /DISCARD/ : { *(.comment) } -} -- cgit v1.2.3 From 94de595afa415626b8f58196f9da2ed899b5d99b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 09:11:01 +0000 Subject: build: update toolchain --- .devcontainer/x86-64/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index a317a22..c23e655 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -1,6 +1,6 @@ { "name": "TeachOS on x86-64", - "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0", + "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0-2", "customizations": { "vscode": { "extensions": [ -- cgit v1.2.3 From f82e0c289d6ab3e901dd80a3cf72aeeb0f85a8c5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 09:15:00 +0000 Subject: build: fix iso generation dependencies --- cmake/Modules/GenerateBootableIso.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/GenerateBootableIso.cmake b/cmake/Modules/GenerateBootableIso.cmake index 368dcf6..4698d6f 100644 --- a/cmake/Modules/GenerateBootableIso.cmake +++ b/cmake/Modules/GenerateBootableIso.cmake @@ -16,7 +16,7 @@ function(target_generate_bootable_iso TARGET) "$/isofs" "$" "2>/dev/null" - BYPRODUCTS "${PROJECT_BINARY_DIR}/$/${TARGET}.iso" + BYPRODUCTS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/${TARGET}.iso" COMMENT "Creating bootable ISO image" ) endfunction() -- cgit v1.2.3 From 3a407e83b2dbd15936569ff90e4433078ea1cbaf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 09:30:34 +0000 Subject: ide: redirect qemu error output --- .gitignore | 6 ++---- .vscode/tasks.json | 6 ++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index d0c36aa..13fb722 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,5 @@ /.conan/install /docs/_build /.cache - -# Conan Generated CMake presets -CMakeUserPresets.json -.gdb_history +/.gdb_history +/qemu-stderr-*.log diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 12ec2ea..f94098e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -17,7 +17,8 @@ "-d", "int,cpu_reset", "-cdrom", - "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.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}/bin/${command:cmake.buildType}/kernel.iso" + "${command:cmake.buildDirectory}/bin/${command:cmake.buildType}/kernel.iso", + "2>${workspaceFolder}/qemu-stderr-${command:cmake.buildType}.log" ], "isBackground": true, "presentation": { -- cgit v1.2.3 From e97e86d169849527190cef1913efdd247e6f68df Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 13:21:32 +0000 Subject: libs: move asm_ptr to kstd --- arch/include/arch/asm_pointer.hpp | 56 -------------------------------- arch/x86_64/include/x86_64/boot/boot.hpp | 8 ++--- arch/x86_64/src/vga/text.cpp | 9 +++-- libs/kstd/CMakeLists.txt | 1 + libs/kstd/include/kstd/asm_ptr | 55 +++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 65 deletions(-) delete mode 100644 arch/include/arch/asm_pointer.hpp create mode 100644 libs/kstd/include/kstd/asm_ptr diff --git a/arch/include/arch/asm_pointer.hpp b/arch/include/arch/asm_pointer.hpp deleted file mode 100644 index c867d8f..0000000 --- a/arch/include/arch/asm_pointer.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef TEACHOS_MEMORY_ASM_POINTER_HPP -#define TEACHOS_MEMORY_ASM_POINTER_HPP - -#include - -namespace teachos::arch -{ - - /** - * @brief A pointer that is defined in some assembly source file. - * - * @tparam Type The type of the pointer - * @since 0.0.1 - */ - template - struct asm_pointer - { - 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_pointer() = delete; - asm_pointer(asm_pointer const &) = delete; - asm_pointer(asm_pointer &&) = delete; - - auto constexpr operator=(asm_pointer const &) = delete; - auto constexpr operator=(asm_pointer &&) = delete; - - auto get() const noexcept -> pointer { return m_ptr; } - - auto constexpr operator+(std::ptrdiff_t offset) const noexcept -> pointer - { - return std::bit_cast(m_ptr) + offset; - } - - auto constexpr operator*() noexcept -> reference { return *(std::bit_cast(m_ptr)); } - - auto constexpr operator*() const noexcept -> const_reference { return *(std::bit_cast(m_ptr)); } - - auto constexpr operator[](std::ptrdiff_t offset) noexcept -> reference { return *(*this + offset); } - - auto constexpr operator[](std::ptrdiff_t offset) const noexcept -> const_reference { return *(*this + offset); } - - auto constexpr operator->() noexcept -> pointer { return m_ptr; } - - auto constexpr operator->() const noexcept -> const_pointer { return m_ptr; } - - private: - pointer m_ptr; - }; - -} // namespace teachos::arch - -#endif // TEACHOS_MEMORY_ASM_POINTER_HPP diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 066e49e..1887e73 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -44,21 +44,21 @@ #else -#include "arch/asm_pointer.hpp" - #include +#include + extern "C" { /** * @brief A pointer to the multiboot 2 information structure provided by the boot loader. */ - extern teachos::arch::asm_pointer multiboot_information_pointer; + extern kstd::asm_ptr multiboot_information_pointer; /** * @brief A pointer to the VGA text mode buffer. */ - extern teachos::arch::asm_pointer> vga_buffer_pointer; + extern kstd::asm_ptr> vga_buffer_pointer; } #endif diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 16abf08..dcfdb6b 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,15 +1,14 @@ #include "x86_64/vga/text.hpp" -#include "arch/asm_pointer.hpp" +#include "x86_64/boot/boot.hpp" #include "x86_64/vga/io.hpp" #include +#include #include #include #include -extern "C" teachos::arch::asm_pointer> vga_buffer_pointer; - namespace teachos::x86_64::vga::text { namespace @@ -23,7 +22,7 @@ namespace teachos::x86_64::vga::text auto clear(attribute attribute) -> void { buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', attribute}); + std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', std::bit_cast(attribute)}); } auto cursor(bool enabled) -> void @@ -54,7 +53,7 @@ namespace teachos::x86_64::vga::text auto write_char(char code_point, attribute attribute) -> void { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, attribute}; + vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; }; auto write(std::string_view code_points, attribute attribute) -> void diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index b0abaaf..ac9e78f 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -13,6 +13,7 @@ target_sources("kstd" PUBLIC "include/kstd/bits/shared_ptr.hpp" "include/kstd/bits/unique_ptr.hpp" + "include/kstd/asm_ptr" "include/kstd/memory" "include/kstd/mutex" "include/kstd/stack" diff --git a/libs/kstd/include/kstd/asm_ptr b/libs/kstd/include/kstd/asm_ptr new file mode 100644 index 0000000..e9072e2 --- /dev/null +++ b/libs/kstd/include/kstd/asm_ptr @@ -0,0 +1,55 @@ +#ifndef KSTD_ASM_POINTER_HPP +#define KSTD_ASM_POINTER_HPP + +#include + +namespace kstd +{ + + /** + * @brief A pointer that is defined in some assembly source file. + * + * @tparam Type The type of the pointer + */ + template + 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; + + auto constexpr operator=(asm_ptr const &) = delete; + auto constexpr operator=(asm_ptr &&) = delete; + + auto get() const noexcept -> pointer { return m_ptr; } + + auto constexpr operator+(std::ptrdiff_t offset) const noexcept -> pointer + { + return std::bit_cast(m_ptr) + offset; + } + + auto constexpr operator*() noexcept -> reference { return *(std::bit_cast(m_ptr)); } + + auto constexpr operator*() const noexcept -> const_reference { return *(std::bit_cast(m_ptr)); } + + auto constexpr operator[](std::ptrdiff_t offset) noexcept -> reference { return *(*this + offset); } + + auto constexpr operator[](std::ptrdiff_t offset) const noexcept -> const_reference { return *(*this + offset); } + + auto constexpr operator->() noexcept -> pointer { return m_ptr; } + + auto constexpr operator->() const noexcept -> const_pointer { return m_ptr; } + + private: + pointer m_ptr; + }; + +} // namespace kstd + +#endif \ No newline at end of file -- cgit v1.2.3 From 29f0e6ad021997e4b6995de4f795781ac381f697 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 13:27:30 +0000 Subject: x86_64: move port_io to x86_64/io --- arch/x86_64/include/arch/io/port_io.hpp | 133 ------------------------------ arch/x86_64/include/x86_64/io/port_io.hpp | 132 +++++++++++++++++++++++++++++ arch/x86_64/include/x86_64/vga/io.hpp | 6 +- 3 files changed, 135 insertions(+), 136 deletions(-) delete mode 100644 arch/x86_64/include/arch/io/port_io.hpp create mode 100644 arch/x86_64/include/x86_64/io/port_io.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 -#include -#include -#include - -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 - 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>; - - /** - * @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/x86_64/io/port_io.hpp b/arch/x86_64/include/x86_64/io/port_io.hpp new file mode 100644 index 0000000..4cf0b65 --- /dev/null +++ b/arch/x86_64/include/x86_64/io/port_io.hpp @@ -0,0 +1,132 @@ +#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP +#define TEACHOS_X86_64_IO_PORT_IO_HPP + +#include +#include +#include + +namespace teachos::x86_64::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 + 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>; + + /** + * @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::x86_64::io + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/vga/io.hpp b/arch/x86_64/include/x86_64/vga/io.hpp index 803dc21..4d99788 100644 --- a/arch/x86_64/include/x86_64/vga/io.hpp +++ b/arch/x86_64/include/x86_64/vga/io.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_IO_HPP #define TEACHOS_X86_64_VGA_IO_HPP -#include "arch/io/port_io.hpp" +#include "x86_64/io/port_io.hpp" #include @@ -12,12 +12,12 @@ namespace teachos::x86_64::vga::io /** * @brief The address port of the CRT Controller. */ - using address_port = arch::io::port<0x3d4, 1>; + using address_port = x86_64::io::port<0x3d4, 1>; /** * @brief The data port of the CRT Controller. */ - using data_port = arch::io::port<0x3d5, 1>; + using data_port = x86_64::io::port<0x3d5, 1>; namespace registers { -- cgit v1.2.3 From be5c7e992ef3f7827e7229d77af3f812484de260 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 13:52:28 +0000 Subject: x86_64: extract linker script interface header --- arch/x86_64/include/x86_64/boot/ld.hpp | 22 ++++++++++++++++++++++ arch/x86_64/src/memory.cpp | 25 +++++++++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 arch/x86_64/include/x86_64/boot/ld.hpp 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..e6b397b --- /dev/null +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -0,0 +1,22 @@ +#ifndef TEACHOS_X86_64_BOOT_LD_H +#define TEACHOS_X86_64_BOOT_LD_H + +#include + +extern "C" +{ + namespace teachos::x86_64::boot + { + /** + * @brief The first byte of the loaded kernel image. + */ + extern "C" std::byte _start_linear; + + /** + * @brief The first byte after the loaded kernel image. + */ + extern "C" std::byte _end_linear; + } // namespace teachos::x86_64::boot +} + +#endif diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index a31627b..105d69b 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -3,22 +3,33 @@ #include "kern/error.hpp" #include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/region_allocator.hpp" #include #include -// extern "C" teachos::arch::asm_pointer multiboot_information_pointer; - namespace teachos::arch::memory { + using namespace x86_64::memory; + using namespace x86_64::boot; + namespace { auto constinit is_initialized = std::atomic_flag{}; - // auto create_memory_information() -> x86_64::memory::region_allocator::memory_information { + auto create_memory_information() -> region_allocator::memory_information + { + auto const & mbi = multiboot_information_pointer.get(); + auto map = mbi->memory_map(); - // }; + return {std::make_pair(physical_address{&_start_linear}, physical_address{&_end_linear}), + std::make_pair(physical_address{std::bit_cast(&mbi)}, + physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + map}; + }; } // namespace auto init() -> void @@ -34,8 +45,10 @@ namespace teachos::arch::memory teachos::panic("[x86_64] No memory map available."); } - // auto mem_info = x86_64::memory::region_allocator::memory_information{}; - // auto allocator = x86_64::memory::region_allocator{mem_info}; + auto mem_info = create_memory_information(); + auto allocator = region_allocator{mem_info}; + + static_cast(allocator); // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 05df795a860eaedf43602beadc2d1637bd2cdd14 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 14:00:08 +0000 Subject: x86_64: improve linker script interface docs - Add file-level Doxygen block to provide overall context. - Clarify the origin of the declared symbols. - Add information regarding their intended use. --- arch/x86_64/include/x86_64/boot/ld.hpp | 51 +++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index e6b397b..6051dd7 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -1,22 +1,47 @@ +/** + * @file + * @brief Provides an interface to linker script defined symbols. + * + * @details + * 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 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. + * + * @see arch/x86_64/scripts/kernel.ld + */ + #ifndef TEACHOS_X86_64_BOOT_LD_H #define TEACHOS_X86_64_BOOT_LD_H #include -extern "C" +namespace teachos::x86_64::boot { - namespace teachos::x86_64::boot - { - /** - * @brief The first byte of the loaded kernel image. - */ - extern "C" std::byte _start_linear; + /** + * @var _start_linear + * @brief The first byte of the loaded kernel image. + * + * @details + * This symbols is defined in the kernel linker script and marks the start of the kernel image in physical memory. + * To use this symbol for its intended purpose, the address of it shall be taken. + * + * @see _end_linear + */ + extern "C" std::byte _start_linear; - /** - * @brief The first byte after the loaded kernel image. - */ - extern "C" std::byte _end_linear; - } // namespace teachos::x86_64::boot -} + /** + * @var _end_linear + * @brief The first byte after the loaded kernel image. + * + * @details + * This symbols is defined in the kernel linker script and marks the end of the kernel image in physical memory. + * To use this symbol for its intended purpose, the address of it shall be taken. + * + * @see _start_linear + */ + extern "C" std::byte _end_linear; +} // namespace teachos::x86_64::boot #endif -- cgit v1.2.3 From bb685cca3a537f0df4205050a9c52b411dee95c6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 14:15:09 +0000 Subject: x86_64: rename _*_linear to _*_physical --- arch/x86_64/include/x86_64/boot/ld.hpp | 12 ++++++------ arch/x86_64/scripts/kernel.ld | 8 ++++---- arch/x86_64/src/memory.cpp | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index 6051dd7..51eb23b 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -20,28 +20,28 @@ namespace teachos::x86_64::boot { /** - * @var _start_linear + * @var _start_physical * @brief The first byte of the loaded kernel image. * * @details * This symbols is defined in the kernel linker script and marks the start of the kernel image in physical memory. * To use this symbol for its intended purpose, the address of it shall be taken. * - * @see _end_linear + * @see _end_physical */ - extern "C" std::byte _start_linear; + extern "C" std::byte _start_physical; /** - * @var _end_linear + * @var _end_physical * @brief The first byte after the loaded kernel image. * * @details * This symbols is defined in the kernel linker script and marks the end of the kernel image in physical memory. * To use this symbol for its intended purpose, the address of it shall be taken. * - * @see _start_linear + * @see _start_physical */ - extern "C" std::byte _end_linear; + extern "C" std::byte _end_physical; } // namespace teachos::x86_64::boot #endif diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 3d9a7ae..8af242f 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -3,7 +3,7 @@ ENTRY(_start) /***************************************************************************** * Virtual and linear start addresses of the TeachOS kernel *****************************************************************************/ -TEACHOS_LOW = 1M; +TEACHOS_PMA = 1M; PHDRS { boot_rodata PT_LOAD FLAGS(4); @@ -22,14 +22,14 @@ 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) * during bootstrapping and operation. To achieve this, we define some * symbols at the beginning. ***************************************************************************/ - _start_linear = .; + _start_physical = .; _start_virtual = .; /*************************************************************************** @@ -144,7 +144,7 @@ SECTIONS * symbols to mark the end of our loaded image. ***************************************************************************/ _end_virtual = ADDR(.bss) + SIZEOF(.bss); - _end_linear = _end_virtual; + _end_physical = _end_virtual; /DISCARD/ : { *(.comment) } } diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 105d69b..b6901a5 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -25,7 +25,7 @@ namespace teachos::arch::memory auto const & mbi = multiboot_information_pointer.get(); auto map = mbi->memory_map(); - return {std::make_pair(physical_address{&_start_linear}, physical_address{&_end_linear}), + return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), std::make_pair(physical_address{std::bit_cast(&mbi)}, physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), map}; -- cgit v1.2.3 From 2ebf8d525e6a030efc8ca23bcbdf92c2d0cb8985 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 10:17:53 +0000 Subject: x86_64: implement high/low split --- .devcontainer/x86-64/devcontainer.json | 2 +- CMakeLists.txt | 1 + arch/CMakeLists.txt | 4 ++ arch/x86_64/scripts/kernel.ld | 35 ++++++----- arch/x86_64/src/boot/boot32.S | 102 +++++++++++++++++++++------------ cmake/Platforms/x86_64.cmake | 24 ++------ 6 files changed, 96 insertions(+), 72 deletions(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index c23e655..3e3b934 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -1,6 +1,6 @@ { "name": "TeachOS on x86-64", - "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0-2", + "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0-3", "customizations": { "vscode": { "extensions": [ diff --git a/CMakeLists.txt b/CMakeLists.txt index 821640c..7c7cc22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ target_link_libraries("kernel" PRIVATE target_link_options("kernel" PRIVATE "-no-pie" + "-nostdlib" ) target_disassemble("kernel") diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt index eded57e..661de26 100644 --- a/arch/CMakeLists.txt +++ b/arch/CMakeLists.txt @@ -16,6 +16,10 @@ target_include_directories("arch-any" INTERFACE target_link_libraries("arch-any" INTERFACE "libs::kstd" + + "c" + "gcc" + "stdc++" ) add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 8af242f..6ba8b80 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -4,6 +4,7 @@ ENTRY(_start) * Virtual and linear start addresses of the TeachOS kernel *****************************************************************************/ TEACHOS_PMA = 1M; +TEACHOS_VMA = 0xFFFFFFFF80000000; PHDRS { boot_rodata PT_LOAD FLAGS(4); @@ -25,12 +26,13 @@ SECTIONS . = 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_physical = .; - _start_virtual = .; + _start_virtual = . + TEACHOS_VMA; + /*************************************************************************** * The bootstrapping infratructure goes first. We first place the read-only @@ -63,7 +65,10 @@ 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)) + . = ALIGN(4K); + . += TEACHOS_VMA; + + .init ALIGN(4K) : AT(ADDR(.init) - TEACHOS_VMA) { /* * Make sure that the crt code is wrapped around the compiler generated @@ -74,7 +79,7 @@ SECTIONS KEEP(*crtn.s.o*(.init)) } :text - .fini ALIGN(4K) : AT(ADDR (.fini)) + .fini ALIGN(4K) : AT(ADDR (.fini) - TEACHOS_VMA) { /* * Make sure that the crt code is wrapped around the compiler generated @@ -85,29 +90,29 @@ SECTIONS KEEP(*crtn.s.o*(.fini)) } - .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 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)) @@ -115,7 +120,7 @@ SECTIONS KEEP(*crtend.o(.ctors)) } :data - .dtors ALIGN(4K) : AT (ADDR (.dtors)) + .dtors ALIGN(4K) : AT (ADDR (.dtors) - TEACHOS_VMA) { KEEP(*crtbegin.o(.dtors)) KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) @@ -123,18 +128,18 @@ SECTIONS KEEP(*crtend.o(.dtors)) } - .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 +148,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_physical = _end_virtual; + _end_virtual = .; + _end_physical = _end_virtual - TEACHOS_VMA; /DISCARD/ : { *(.comment) } } diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 7e6c2ae..3039f38 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -13,9 +13,13 @@ multiboot_information_pointer: .skip 8 .align 4096 -page_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 +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. @@ -40,9 +44,9 @@ global_descriptor_table: global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE +.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_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT +.quad GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | (1 << 54) | (1 << 55) global_descriptor_table_end: message_prefix_panic: .string "Panic: " @@ -125,7 +129,10 @@ _start: 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 @@ -302,51 +309,74 @@ _assert_cpu_supports_long_mode: /** * @brief Prepare a recursive page map hierarchy * - * 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. - * + * @param ebp+8 The number of huge pages to map * @return void */ _prepare_page_maps: pie_function_start - push %ebx - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx + + 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, (%ebx, %ecx, 8) + mov %eax, (%edi, %ecx, 8) - inc %ecx - cmp %edi, %ecx - jne 1b + test %ecx, %ecx + jnz 1b pop %edi - pop %ebx + + 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 /** diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index c84d9ba..8db6142 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -1,17 +1,5 @@ include_guard(GLOBAL) -macro(find_compiler_file NAME OUTPUT_VARIABLE) - execute_process(COMMAND - "${CMAKE_CXX_COMPILER}" - "-mno-red-zone" - "-print-file-name=${NAME}" - OUTPUT_STRIP_TRAILING_WHITESPACE - OUTPUT_VARIABLE "${OUTPUT_VARIABLE}" - ERROR_QUIET - ) - mark_as_advanced("${OUTPUT_VARIABLE}") -endmacro() - set(PLATFORM_TARGET "x86_64-pc-elf") set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") @@ -27,7 +15,8 @@ find_program(CMAKE_CXX_COMPILER "${CMAKE_CXX_COMPILER_TARGET}-g++" REQUIRED) set(CMAKE_CXX_FLAGS_INIT "-mno-red-zone \ --mcmodel=large \ +-mcmodel=kernel \ +-fno-pie \ -fno-rtti \ -fno-exceptions \ -ffunction-sections \ @@ -46,19 +35,14 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb3") set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3") -set(CMAKE_EXE_LINKER_FLAGS_INIT "-nostartfiles -Wl,--gc-sections") - -find_compiler_file("crtbegin.o" CRT_BEGIN_PATH) -find_compiler_file("crtend.o" CRT_END_PATH) +set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,--gc-sections") set(CMAKE_CXX_LINK_EXECUTABLE " \ \ \ \ -${CRT_BEGIN_PATH} \ \ -o \ - \ -${CRT_END_PATH}" +" ) -- cgit v1.2.3 From f62b05c93c6c539d899d2656c0638d404a036f1a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 12:28:23 +0000 Subject: x86_64: implement robust C++ global initialization Implement a comprehensive mechanism to ensure correct C++ runtime initialization before the kernel main function is called. This replaces the previous, incomplete reliance on an `_init` function. The new design robustly handles both legacy `.ctors` and modern `.init_array` initialization schemes used by the GNU toolchain. A single C++ function, `invoke_global_constructors`, now iterates through both arrays of function pointers to ensure all types of global initializers are executed. --- arch/x86_64/CMakeLists.txt | 3 +-- arch/x86_64/scripts/kernel.ld | 40 +++++++---------------------- arch/x86_64/src/boot/crti.s | 13 ---------- arch/x86_64/src/boot/crtn.s | 9 ------- arch/x86_64/src/boot/entry64.s | 4 +-- arch/x86_64/src/boot/initialize_runtime.cpp | 24 +++++++++++++++++ 6 files changed, 36 insertions(+), 57 deletions(-) delete mode 100644 arch/x86_64/src/boot/crti.s delete mode 100644 arch/x86_64/src/boot/crtn.s create mode 100644 arch/x86_64/src/boot/initialize_runtime.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 6bb9e53..58daa3b 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -35,9 +35,8 @@ target_sources("arch-x86_64" PRIVATE target_sources("arch-x86_64" PRIVATE "src/boot/boot32.S" - "src/boot/crti.s" - "src/boot/crtn.s" "src/boot/entry64.s" + "src/boot/initialize_runtime.cpp" "src/boot/multiboot.s" ) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 6ba8b80..064b8d7 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -68,33 +68,11 @@ SECTIONS . = ALIGN(4K); . += TEACHOS_VMA; - .init ALIGN(4K) : AT(ADDR(.init) - TEACHOS_VMA) - { - /* - * 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) - TEACHOS_VMA) - { - /* - * 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)) - } - .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) - TEACHOS_VMA) { @@ -114,18 +92,18 @@ SECTIONS .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) - TEACHOS_VMA) + .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) - TEACHOS_VMA) 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 index f575c50..110ced8 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -12,8 +12,8 @@ _entry64: xor %rax, %rax - call _init - + call invoke_global_constructors + call main 1: 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..9a3df0e --- /dev/null +++ b/arch/x86_64/src/boot/initialize_runtime.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +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) { return std::invoke(invokable); }; + + std::ranges::for_each(constructors, apply_invoke); + std::ranges::for_each(initializers, apply_invoke); + } +} -- cgit v1.2.3 From c984e3980ab7cb939486d341a89744a99a785f77 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 12:54:55 +0000 Subject: x86_64: update toolchain --- .devcontainer/x86-64/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index 3e3b934..6b76902 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -1,6 +1,6 @@ { "name": "TeachOS on x86-64", - "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0-3", + "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0-4", "customizations": { "vscode": { "extensions": [ -- cgit v1.2.3 From 017e6e1f8eb413e86738d2f2cfb4e8b29ebe26dc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 13:16:20 +0000 Subject: build: clean up x86_64 toolchain --- cmake/Platforms/x86_64.cmake | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index 8db6142..f969cb3 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -23,6 +23,8 @@ set(CMAKE_CXX_FLAGS_INIT -fdata-sections" ) +set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,--gc-sections") + set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3") set(CMAKE_ASM_FLAGS_DEBUG "-ggdb3") @@ -34,15 +36,3 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb3") set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -DNDEBUG -ggdb3") - -set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,--gc-sections") - -set(CMAKE_CXX_LINK_EXECUTABLE -" \ - \ - \ - \ - \ --o \ -" -) -- cgit v1.2.3 From 20aed7283195c1b9ac86e4e98a61f083f05b1513 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 13:16:44 +0000 Subject: build: fix doc comment in main configuration --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c7cc22..91b4b6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ add_compile_options( ) #[============================================================================[ -# Global Build System Configuration +# Kernel Executable #]============================================================================] add_executable("kernel") -- cgit v1.2.3 From 187788deaf81a0ef6709aea8f3c4d906f1669762 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 13:17:13 +0000 Subject: build: remove unused code in main configuration --- CMakeLists.txt | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91b4b6d..9a6dabc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,49 +56,3 @@ target_extract_debug_symbols("kernel") target_strip("kernel") target_generate_bootable_iso("kernel") - -#[============================================================================[ -# 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" -# ) - -- cgit v1.2.3 From ef907825e861b63726952bb34b425a98f34ed412 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 13:52:42 +0000 Subject: x86_64: provide a clean slate on entry to long mode --- arch/x86_64/src/boot/boot32.S | 4 ++++ arch/x86_64/src/boot/entry64.s | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 3039f38..27eed4d 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -27,8 +27,12 @@ page_maps_size = page_maps_end - page_maps_start .section .boot_stack, "aw", @nobits .align 16 +.global stack_size +.global stack_bottom + stack_bottom: .skip 1 << 20 stack_top: +stack_size = stack_top - stack_bottom /** * @brief Constants for the bootstrapping process. diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index 110ced8..c5df5db 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -10,10 +10,20 @@ _entry64: mov %rax, %fs mov %rax, %gs - xor %rax, %rax - 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: -- cgit v1.2.3 From 2b8fafa2bddc48ddec047de517115c8e65ee61e8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 15:05:17 +0000 Subject: build: move linker script dependency to kernel --- CMakeLists.txt | 7 +++++++ arch/CMakeLists.txt | 2 ++ arch/x86_64/CMakeLists.txt | 8 -------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a6dabc..aa1f6a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,10 +47,17 @@ target_link_libraries("kernel" PRIVATE ) 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") diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt index 661de26..83da439 100644 --- a/arch/CMakeLists.txt +++ b/arch/CMakeLists.txt @@ -23,3 +23,5 @@ target_link_libraries("arch-any" INTERFACE ) add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") + +set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/scripts/kernel.ld" PARENT_SCOPE) diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 58daa3b..431520e 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -11,14 +11,6 @@ target_link_libraries("arch-x86_64" PUBLIC "libs::multiboot2" ) -target_link_options("arch-x86_64" PUBLIC - "-T${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" -) - -set_target_properties("arch-x86_64" PROPERTIES - LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" -) - #[============================================================================[ # arch::any Implementation #]============================================================================] -- cgit v1.2.3 From 4edbe94ce1266c9acc6a695fedf1d2edd4ce11cd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 15:31:31 +0000 Subject: build: factor out kernel API --- .clang-format | 7 ++---- CMakeLists.txt | 14 +++++++----- arch/CMakeLists.txt | 26 +--------------------- arch/include/arch/io.hpp | 9 -------- arch/include/arch/memory.hpp | 9 -------- arch/include/arch/system.hpp | 9 -------- arch/x86_64/CMakeLists.txt | 3 +-- arch/x86_64/src/io.cpp | 44 ++++++++++++++++++++++---------------- arch/x86_64/src/memory.cpp | 12 +++++------ arch/x86_64/src/system.cpp | 6 +++--- kapi/CMakeLists.txt | 27 +++++++++++++++++++++++ kapi/include/kapi/io.hpp | 17 +++++++++++++++ kapi/include/kapi/memory.hpp | 9 ++++++++ kapi/include/kapi/system.hpp | 14 ++++++++++++ kapi/src/system.cpp | 18 ++++++++++++++++ kern/CMakeLists.txt | 18 ---------------- kern/include/kern/error.hpp | 13 ----------- kern/include/kern/print.hpp | 26 ---------------------- kern/src/abort.cpp | 3 --- kern/src/error.cpp | 19 ----------------- kern/src/kstd.cpp | 10 --------- kern/src/main.cpp | 14 ------------ kern/src/print.cpp | 51 -------------------------------------------- src/abort.cpp | 3 +++ src/kstd.cpp | 13 +++++++++++ src/main.cpp | 13 +++++++++++ 26 files changed, 162 insertions(+), 245 deletions(-) delete mode 100644 arch/include/arch/io.hpp delete mode 100644 arch/include/arch/memory.hpp delete mode 100644 arch/include/arch/system.hpp create mode 100644 kapi/CMakeLists.txt create mode 100644 kapi/include/kapi/io.hpp create mode 100644 kapi/include/kapi/memory.hpp create mode 100644 kapi/include/kapi/system.hpp create mode 100644 kapi/src/system.cpp delete mode 100644 kern/CMakeLists.txt delete mode 100644 kern/include/kern/error.hpp delete mode 100644 kern/include/kern/print.hpp delete mode 100644 kern/src/abort.cpp delete mode 100644 kern/src/error.cpp delete mode 100644 kern/src/kstd.cpp delete mode 100644 kern/src/main.cpp delete mode 100644 kern/src/print.cpp create mode 100644 src/abort.cpp create mode 100644 src/kstd.cpp create mode 100644 src/main.cpp diff --git a/.clang-format b/.clang-format index b32e8c9..714f716 100644 --- a/.clang-format +++ b/.clang-format @@ -40,12 +40,9 @@ DerivePointerAlignment: 'false' FixNamespaceComments: 'true' IncludeBlocks: Regroup IncludeCategories: - # Kernel Headers - - Regex: 'kern/[[:alnum:]._\/]+\.hpp' + # Kernel API Headers + - Regex: 'kapi/[[:alnum:]._\/]+\.hpp' Priority: 100 - # Architecture Interface Headers - - Regex: 'arch/[[:alnum:]._\/]+\.hpp' - Priority: 110 # Architecture Implementation Headers - Regex: 'x86_64/[[:alnum:]._\/]+\.hpp' Priority: 110 diff --git a/CMakeLists.txt b/CMakeLists.txt index aa1f6a9..5dd4044 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,15 +35,19 @@ add_compile_options( # Kernel Executable #]============================================================================] -add_executable("kernel") - -add_subdirectory("libs") -add_subdirectory("kern") add_subdirectory("arch") +add_subdirectory("kapi") +add_subdirectory("libs") + +add_executable("kernel" + "src/abort.cpp" + "src/kstd.cpp" + "src/main.cpp" +) target_link_libraries("kernel" PRIVATE "arch::${CMAKE_SYSTEM_PROCESSOR}" - "os::kern" + "api::kapi" ) target_link_options("kernel" PRIVATE diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt index 83da439..516bfe9 100644 --- a/arch/CMakeLists.txt +++ b/arch/CMakeLists.txt @@ -1,27 +1,3 @@ -add_library("arch-any" INTERFACE) -add_library("arch::any" ALIAS "arch-any") - -target_sources("arch-any" INTERFACE - FILE_SET HEADERS - BASE_DIRS "include" - FILES - "include/arch/io.hpp" - "include/arch/memory.hpp" - "include/arch/system.hpp" -) - -target_include_directories("arch-any" INTERFACE - "include" -) - -target_link_libraries("arch-any" INTERFACE - "libs::kstd" - - "c" - "gcc" - "stdc++" -) +set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/scripts/kernel.ld" PARENT_SCOPE) add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") - -set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/scripts/kernel.ld" PARENT_SCOPE) diff --git a/arch/include/arch/io.hpp b/arch/include/arch/io.hpp deleted file mode 100644 index 8986b9c..0000000 --- a/arch/include/arch/io.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef TEACHOS_ARCH_IO_HPP -#define TEACHOS_ARCH_IO_HPP - -namespace teachos::arch::io -{ - auto init() -> void; -} - -#endif diff --git a/arch/include/arch/memory.hpp b/arch/include/arch/memory.hpp deleted file mode 100644 index 33f7fdd..0000000 --- a/arch/include/arch/memory.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef TEACHOS_ARCH_MEMORY_HPP -#define TEACHOS_ARCH_MEMORY_HPP - -namespace teachos::arch::memory -{ - auto init() -> void; -} - -#endif diff --git a/arch/include/arch/system.hpp b/arch/include/arch/system.hpp deleted file mode 100644 index 73e2463..0000000 --- a/arch/include/arch/system.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef TEACHOS_ARCH_SYSTEM_HPP -#define TEACHOS_ARCH_SYSTEM_HPP - -namespace teachos::arch::system -{ - [[noreturn]] auto halt() -> void; -} - -#endif diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 431520e..4cb20b6 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -6,8 +6,7 @@ target_include_directories("arch-x86_64" PUBLIC ) target_link_libraries("arch-x86_64" PUBLIC - "arch::any" - "os::kern" + "api::kapi" "libs::multiboot2" ) diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp index 8e9e411..eab6473 100644 --- a/arch/x86_64/src/io.cpp +++ b/arch/x86_64/src/io.cpp @@ -1,28 +1,36 @@ -#include "kern/print.hpp" +#include "kapi/io.hpp" + #include "x86_64/vga/text.hpp" -namespace teachos::arch::io +namespace teachos::io { auto init() -> void { + x86_64::vga::text::clear(); x86_64::vga::text::cursor(false); + } + + auto print(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + } + + auto println(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + x86_64::vga::text::newline(); + } + + auto print_error(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + } - teachos::set_print_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); - teachos::set_println_handler([](auto text) { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - x86_64::vga::text::newline(); - }); - - teachos::set_print_error_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); - teachos::set_println_error_handler([](auto text) { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - x86_64::vga::text::newline(); - }); - - teachos::println("[x86-64] Basic VGA text output initialized."); + auto println_error(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + x86_64::vga::text::newline(); } -} // namespace teachos::arch::io +} // namespace teachos::io diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index b6901a5..d1c1f03 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -1,6 +1,6 @@ -#include "arch/memory.hpp" +#include "kapi/memory.hpp" -#include "kern/error.hpp" +#include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" @@ -11,7 +11,7 @@ #include -namespace teachos::arch::memory +namespace teachos::memory { using namespace x86_64::memory; using namespace x86_64::boot; @@ -36,13 +36,13 @@ namespace teachos::arch::memory { if (is_initialized.test_and_set()) { - teachos::panic("[x86_64] Memory management has already been initialized."); + system::panic("[x86_64] Memory management has already been initialized."); } auto memory_map = multiboot_information_pointer->maybe_memory_map(); if (!memory_map) { - teachos::panic("[x86_64] No memory map available."); + system::panic("[x86_64] No memory map available."); } auto mem_info = create_memory_information(); @@ -63,4 +63,4 @@ namespace teachos::arch::memory // video::vga::text::newline(); } -} // namespace teachos::arch::memory +} // namespace teachos::memory diff --git a/arch/x86_64/src/system.cpp b/arch/x86_64/src/system.cpp index 60ebf0e..2d4c3fe 100644 --- a/arch/x86_64/src/system.cpp +++ b/arch/x86_64/src/system.cpp @@ -1,6 +1,6 @@ -#include "arch/system.hpp" +#include "kapi/system.hpp" -namespace teachos::arch::system +namespace teachos::system { auto halt() -> void @@ -9,4 +9,4 @@ namespace teachos::arch::system __builtin_unreachable(); } -} // namespace teachos::arch::system +} // namespace teachos::system diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt new file mode 100644 index 0000000..a3cd040 --- /dev/null +++ b/kapi/CMakeLists.txt @@ -0,0 +1,27 @@ +add_library("kapi" OBJECT) +add_library("api::kapi" ALIAS "kapi") + +target_sources("kapi" PUBLIC + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/kapi/io.hpp" + "include/kapi/memory.hpp" + "include/kapi/system.hpp" +) + +target_sources("kapi" PRIVATE + "src/system.cpp" +) + +target_include_directories("kapi" PUBLIC + "include" +) + +target_link_libraries("kapi" PUBLIC + "libs::kstd" + + "c" + "gcc" + "stdc++" +) diff --git a/kapi/include/kapi/io.hpp b/kapi/include/kapi/io.hpp new file mode 100644 index 0000000..764738f --- /dev/null +++ b/kapi/include/kapi/io.hpp @@ -0,0 +1,17 @@ +#ifndef TEACHOS_KAPI_IO_HPP +#define TEACHOS_KAPI_IO_HPP + +#include + +namespace teachos::io +{ + auto init() -> void; + + auto print(std::string_view text) -> void; + auto println(std::string_view text) -> void; + + auto print_error(std::string_view text) -> void; + auto println_error(std::string_view text) -> void; +} // namespace teachos::io + +#endif diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp new file mode 100644 index 0000000..842a2fa --- /dev/null +++ b/kapi/include/kapi/memory.hpp @@ -0,0 +1,9 @@ +#ifndef TEACHOS_KAPI_MEMORY_HPP +#define TEACHOS_KAPI_MEMORY_HPP + +namespace teachos::memory +{ + auto init() -> void; +} + +#endif diff --git a/kapi/include/kapi/system.hpp b/kapi/include/kapi/system.hpp new file mode 100644 index 0000000..0d4f2c9 --- /dev/null +++ b/kapi/include/kapi/system.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_KAPI_SYSTEM_HPP +#define TEACHOS_KAPI_SYSTEM_HPP + +#include +#include + +namespace teachos::system +{ + [[noreturn]] auto halt() -> void; + + [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; +} // namespace teachos::system + +#endif diff --git a/kapi/src/system.cpp b/kapi/src/system.cpp new file mode 100644 index 0000000..c3b1c5e --- /dev/null +++ b/kapi/src/system.cpp @@ -0,0 +1,18 @@ +#include "kapi/system.hpp" + +#include "kapi/io.hpp" + +namespace teachos::system +{ + + auto panic(std::string_view message, std::source_location location) -> void + { + io::println_error("!!!Kernel Panic!!! "); + io::println_error(message); + io::println_error(location.file_name()); + io::println_error(location.function_name()); + + halt(); + } + +} // namespace teachos::system diff --git a/kern/CMakeLists.txt b/kern/CMakeLists.txt deleted file mode 100644 index 677fdc2..0000000 --- a/kern/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_library("kern" OBJECT) -add_library("os::kern" ALIAS "kern") - -target_sources("kern" PRIVATE - "src/abort.cpp" - "src/error.cpp" - "src/kstd.cpp" - "src/main.cpp" - "src/print.cpp" -) - -target_include_directories("kern" PUBLIC - "include" -) - -target_link_libraries("kern" PUBLIC - "arch::any" -) diff --git a/kern/include/kern/error.hpp b/kern/include/kern/error.hpp deleted file mode 100644 index e58b9f1..0000000 --- a/kern/include/kern/error.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_KERN_ERROR_HPP -#define TEACHOS_KERN_ERROR_HPP - -#include -#include - -namespace teachos -{ - [[noreturn]] - auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; -} - -#endif diff --git a/kern/include/kern/print.hpp b/kern/include/kern/print.hpp deleted file mode 100644 index fc9b5d6..0000000 --- a/kern/include/kern/print.hpp +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef TEACHOS_KERN_PRINT_HPP -#define TEACHOS_KERN_PRINT_HPP - -#include - -namespace teachos -{ - - using print_handler = auto(std::string_view) -> void; - using println_handler = auto(std::string_view) -> void; - - auto print(std::string_view text) -> void; - auto println(std::string_view text) -> void; - - auto print_error(std::string_view text) -> void; - auto println_error(std::string_view text) -> void; - - auto set_print_handler(print_handler handler) -> print_handler *; - auto set_println_handler(println_handler handler) -> print_handler *; - auto set_print_error_handler(print_handler handler) -> print_handler *; - auto set_println_error_handler(println_handler handler) -> print_handler *; - -} // namespace teachos - -#endif diff --git a/kern/src/abort.cpp b/kern/src/abort.cpp deleted file mode 100644 index 6db0b74..0000000 --- a/kern/src/abort.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "kern/error.hpp" - -extern "C" [[noreturn]] auto abort() -> void { teachos::panic("Abort called"); } diff --git a/kern/src/error.cpp b/kern/src/error.cpp deleted file mode 100644 index a5229fd..0000000 --- a/kern/src/error.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "kern/error.hpp" - -#include "arch/system.hpp" -#include "kern/print.hpp" - -namespace teachos -{ - - auto panic(std::string_view message, std::source_location location) -> void - { - println_error("!!!Kernel Panic!!! "); - println_error(message); - println_error(location.file_name()); - println_error(location.function_name()); - - arch::system::halt(); - } - -} // namespace teachos diff --git a/kern/src/kstd.cpp b/kern/src/kstd.cpp deleted file mode 100644 index 1b7050b..0000000 --- a/kern/src/kstd.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "kern/error.hpp" - -#include - -namespace kstd::os -{ - - auto panic(std::string_view message, std::source_location location) -> void { teachos::panic(message, location); } - -} // namespace kstd::os \ No newline at end of file diff --git a/kern/src/main.cpp b/kern/src/main.cpp deleted file mode 100644 index b99fb37..0000000 --- a/kern/src/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "arch/io.hpp" -#include "arch/memory.hpp" -#include "kern/error.hpp" -#include "kern/print.hpp" - -auto main() -> int -{ - teachos::arch::io::init(); - teachos::println("[OS] IO subsystem initialized."); - - teachos::arch::memory::init(); - - teachos::panic("Architecture specific main returned!"); -} diff --git a/kern/src/print.cpp b/kern/src/print.cpp deleted file mode 100644 index 2c8539b..0000000 --- a/kern/src/print.cpp +++ /dev/null @@ -1,51 +0,0 @@ - -#include "kern/print.hpp" - -#include - -namespace teachos -{ - namespace - { - constinit auto noop = [](std::string_view) {}; - - constinit auto current_print_handler = static_cast(noop); - constinit auto current_println_handler = static_cast(noop); - constinit auto current_print_error_handler = static_cast(noop); - constinit auto current_println_error_handler = static_cast(noop); - } // namespace - - auto print(std::string_view text) -> void { current_print_handler(text); } - auto println(std::string_view text) -> void { current_println_handler(text); } - auto print_error(std::string_view text) -> void { current_print_error_handler(text); } - auto println_error(std::string_view text) -> void { current_println_error_handler(text); } - - auto set_print_handler(print_handler handler) -> print_handler * - { - auto old = current_print_handler; - current_print_handler = handler; - return old; - } - - auto set_println_handler(println_handler handler) -> print_handler * - { - auto old = current_println_handler; - current_println_handler = handler; - return old; - } - - auto set_print_error_handler(print_handler handler) -> print_handler * - { - auto old = current_print_error_handler; - current_print_error_handler = handler; - return old; - } - - auto set_println_error_handler(println_handler handler) -> print_handler * - { - auto old = current_println_error_handler; - current_println_error_handler = handler; - return old; - } - -} // namespace teachos diff --git a/src/abort.cpp b/src/abort.cpp new file mode 100644 index 0000000..6b0070e --- /dev/null +++ b/src/abort.cpp @@ -0,0 +1,3 @@ +#include "kapi/system.hpp" + +extern "C" [[noreturn]] auto abort() -> void { teachos::system::panic("Abort called"); } diff --git a/src/kstd.cpp b/src/kstd.cpp new file mode 100644 index 0000000..2149c12 --- /dev/null +++ b/src/kstd.cpp @@ -0,0 +1,13 @@ +#include "kapi/system.hpp" + +#include + +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/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d6199d0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,13 @@ +#include "kapi/io.hpp" +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +auto main() -> int +{ + teachos::io::init(); + teachos::io::println("[OS] IO subsystem initialized."); + + teachos::memory::init(); + + teachos::system::panic("Architecture specific main returned!"); +} -- cgit v1.2.3 From c6629ba11c17601695b0542d7d1d1bf5dc036d84 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 15:37:36 +0000 Subject: build: clean up configuration --- CMakeLists.txt | 2 +- arch/CMakeLists.txt | 3 - arch/x86_64/CMakeLists.txt | 192 +++----------------------------------------- arch/x86_64/kapi/io.cpp | 36 +++++++++ arch/x86_64/kapi/memory.cpp | 66 +++++++++++++++ arch/x86_64/kapi/system.cpp | 12 +++ arch/x86_64/src/io.cpp | 36 --------- arch/x86_64/src/memory.cpp | 66 --------------- arch/x86_64/src/system.cpp | 12 --- 9 files changed, 126 insertions(+), 299 deletions(-) delete mode 100644 arch/CMakeLists.txt create mode 100644 arch/x86_64/kapi/io.cpp create mode 100644 arch/x86_64/kapi/memory.cpp create mode 100644 arch/x86_64/kapi/system.cpp delete mode 100644 arch/x86_64/src/io.cpp delete mode 100644 arch/x86_64/src/memory.cpp delete mode 100644 arch/x86_64/src/system.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dd4044..64fb08f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ add_compile_options( # Kernel Executable #]============================================================================] -add_subdirectory("arch") +add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") add_subdirectory("kapi") add_subdirectory("libs") diff --git a/arch/CMakeLists.txt b/arch/CMakeLists.txt deleted file mode 100644 index 516bfe9..0000000 --- a/arch/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/scripts/kernel.ld" PARENT_SCOPE) - -add_subdirectory("${CMAKE_SYSTEM_PROCESSOR}") diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4cb20b6..1cb2f9a 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -10,196 +10,26 @@ target_link_libraries("arch-x86_64" PUBLIC "libs::multiboot2" ) -#[============================================================================[ -# arch::any Implementation -#]============================================================================] - target_sources("arch-x86_64" PRIVATE - "src/io.cpp" - "src/memory.cpp" - "src/system.cpp" -) - -#[============================================================================[ -# Bootstrap Code -#]============================================================================] + # api::kapi implementation + "kapi/io.cpp" + "kapi/memory.cpp" + "kapi/system.cpp" -target_sources("arch-x86_64" PRIVATE + # Low-level bootstrap "src/boot/boot32.S" "src/boot/entry64.s" "src/boot/initialize_runtime.cpp" "src/boot/multiboot.s" -) -#[============================================================================[ -# Memory Code -#]============================================================================] - -target_sources("arch-x86_64" PRIVATE + # Memory management "src/memory/region_allocator.cpp" -) - -#[============================================================================[ -# VGA Code -#]============================================================================] -target_sources("arch-x86_64" PRIVATE + # VGA text mode "src/vga/text.cpp" ) -# #[============================================================================[ -# # The Kernel Library -# #]============================================================================] - -# 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}" -# ) - -# set_target_properties("_kernel" PROPERTIES -# LINK_DEPENDS "${TEACHOS_KERNEL_LINKER_SCRIPT}" -# ) - -# #[============================================================================[ -# # The Bootstrap Library -# #]============================================================================] - -# target_sources("_boot" PRIVATE -# "src/boot/boot.s" -# "src/boot/crti.s" -# "src/boot/crtn.s" -# "src/boot/multiboot.s" -# ) - -# #[============================================================================[ -# # The Video Library -# #]============================================================================] - -# target_sources("_video" PRIVATE -# "src/video/vga/text.cpp" -# ) - -# #[============================================================================[ -# # The Memory Library -# #]============================================================================] - -# 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_link_libraries("_memory" PUBLIC -# "libs::kstd" -# "libs::multiboot2" -# ) - -# #[============================================================================[ -# # 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" -# ) - -# target_link_libraries("_context" PUBLIC -# "libs::kstd" -# ) - -# #[============================================================================[ -# # 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-$.iso" -# "${CMAKE_CURRENT_BINARY_DIR}/isofs" -# "$" -# "2>/dev/null" -# DEPENDS -# "$" -# "isofs/boot/grub/grub.cfg" -# BYPRODUCTS "${PROJECT_BINARY_DIR}/teachos-$.iso" -# COMMENT "Creating bootable ISO image" -# ) -# endif() +set(KERNEL_LINKER_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" + PARENT_SCOPE +) \ No newline at end of file diff --git a/arch/x86_64/kapi/io.cpp b/arch/x86_64/kapi/io.cpp new file mode 100644 index 0000000..eab6473 --- /dev/null +++ b/arch/x86_64/kapi/io.cpp @@ -0,0 +1,36 @@ +#include "kapi/io.hpp" + +#include "x86_64/vga/text.hpp" + +namespace teachos::io +{ + + auto init() -> void + { + x86_64::vga::text::clear(); + x86_64::vga::text::cursor(false); + } + + auto print(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + } + + auto println(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + x86_64::vga::text::newline(); + } + + auto print_error(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + } + + auto println_error(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + x86_64::vga::text::newline(); + } + +} // namespace teachos::io diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp new file mode 100644 index 0000000..d1c1f03 --- /dev/null +++ b/arch/x86_64/kapi/memory.cpp @@ -0,0 +1,66 @@ +#include "kapi/memory.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/region_allocator.hpp" + +#include + +#include + +namespace teachos::memory +{ + using namespace x86_64::memory; + using namespace x86_64::boot; + + namespace + { + auto constinit is_initialized = std::atomic_flag{}; + + auto create_memory_information() -> region_allocator::memory_information + { + auto const & mbi = multiboot_information_pointer.get(); + auto map = mbi->memory_map(); + + return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), + std::make_pair(physical_address{std::bit_cast(&mbi)}, + physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + map}; + }; + } // namespace + + auto init() -> void + { + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] Memory management has already been initialized."); + } + + auto memory_map = multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + system::panic("[x86_64] No memory map available."); + } + + auto mem_info = create_memory_information(); + auto allocator = region_allocator{mem_info}; + + static_cast(allocator); + + // 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::memory diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp new file mode 100644 index 0000000..2d4c3fe --- /dev/null +++ b/arch/x86_64/kapi/system.cpp @@ -0,0 +1,12 @@ +#include "kapi/system.hpp" + +namespace teachos::system +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace teachos::system diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp deleted file mode 100644 index eab6473..0000000 --- a/arch/x86_64/src/io.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "kapi/io.hpp" - -#include "x86_64/vga/text.hpp" - -namespace teachos::io -{ - - auto init() -> void - { - x86_64::vga::text::clear(); - x86_64::vga::text::cursor(false); - } - - auto print(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - } - - auto println(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - x86_64::vga::text::newline(); - } - - auto print_error(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - } - - auto println_error(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - x86_64::vga::text::newline(); - } - -} // namespace teachos::io diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp deleted file mode 100644 index d1c1f03..0000000 --- a/arch/x86_64/src/memory.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "kapi/memory.hpp" - -#include "kapi/system.hpp" - -#include "x86_64/boot/boot.hpp" -#include "x86_64/boot/ld.hpp" -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/region_allocator.hpp" - -#include - -#include - -namespace teachos::memory -{ - using namespace x86_64::memory; - using namespace x86_64::boot; - - namespace - { - auto constinit is_initialized = std::atomic_flag{}; - - auto create_memory_information() -> region_allocator::memory_information - { - auto const & mbi = multiboot_information_pointer.get(); - auto map = mbi->memory_map(); - - return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), - std::make_pair(physical_address{std::bit_cast(&mbi)}, - physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), - map}; - }; - } // namespace - - auto init() -> void - { - if (is_initialized.test_and_set()) - { - system::panic("[x86_64] Memory management has already been initialized."); - } - - auto memory_map = multiboot_information_pointer->maybe_memory_map(); - if (!memory_map) - { - system::panic("[x86_64] No memory map available."); - } - - auto mem_info = create_memory_information(); - auto allocator = region_allocator{mem_info}; - - static_cast(allocator); - - // 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::memory diff --git a/arch/x86_64/src/system.cpp b/arch/x86_64/src/system.cpp deleted file mode 100644 index 2d4c3fe..0000000 --- a/arch/x86_64/src/system.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "kapi/system.hpp" - -namespace teachos::system -{ - - auto halt() -> void - { - asm volatile("1: hlt\njmp 1b"); - __builtin_unreachable(); - } - -} // namespace teachos::system -- cgit v1.2.3 From f00a0149b55a0fd57cc731b015c6f425bc720aba Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 15:41:58 +0000 Subject: build: rename targets --- CMakeLists.txt | 4 ++-- arch/x86_64/CMakeLists.txt | 12 ++++++------ kapi/CMakeLists.txt | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64fb08f..3251847 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,8 +46,8 @@ add_executable("kernel" ) target_link_libraries("kernel" PRIVATE - "arch::${CMAKE_SYSTEM_PROCESSOR}" - "api::kapi" + "os::arch" + "os::kapi" ) target_link_options("kernel" PRIVATE diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1cb2f9a..ddc2d46 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -1,16 +1,16 @@ -add_library("arch-x86_64" OBJECT) -add_library("arch::x86_64" ALIAS "arch-x86_64") +add_library("x86_64" OBJECT) +add_library("os::arch" ALIAS "x86_64") -target_include_directories("arch-x86_64" PUBLIC +target_include_directories("x86_64" PUBLIC "include" ) -target_link_libraries("arch-x86_64" PUBLIC - "api::kapi" +target_link_libraries("x86_64" PUBLIC + "os::kapi" "libs::multiboot2" ) -target_sources("arch-x86_64" PRIVATE +target_sources("x86_64" PRIVATE # api::kapi implementation "kapi/io.cpp" "kapi/memory.cpp" diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index a3cd040..3a15fee 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -1,5 +1,5 @@ add_library("kapi" OBJECT) -add_library("api::kapi" ALIAS "kapi") +add_library("os::kapi" ALIAS "kapi") target_sources("kapi" PUBLIC FILE_SET HEADERS -- cgit v1.2.3 From 3b9bbbb4be529f2365b8bc2e43c1c8e9a65b1a07 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:15:31 +0000 Subject: x86_64: clean up vga hierarchy --- arch/x86_64/include/x86_64/device_io/port_io.hpp | 132 +++++++++++++++++++++++ arch/x86_64/include/x86_64/io/port_io.hpp | 132 ----------------------- arch/x86_64/include/x86_64/vga/crtc.hpp | 35 ++++++ arch/x86_64/include/x86_64/vga/io.hpp | 39 ------- arch/x86_64/src/vga/text.cpp | 6 +- 5 files changed, 170 insertions(+), 174 deletions(-) create mode 100644 arch/x86_64/include/x86_64/device_io/port_io.hpp delete mode 100644 arch/x86_64/include/x86_64/io/port_io.hpp create mode 100644 arch/x86_64/include/x86_64/vga/crtc.hpp delete mode 100644 arch/x86_64/include/x86_64/vga/io.hpp 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..4cf0b65 --- /dev/null +++ b/arch/x86_64/include/x86_64/device_io/port_io.hpp @@ -0,0 +1,132 @@ +#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP +#define TEACHOS_X86_64_IO_PORT_IO_HPP + +#include +#include +#include + +namespace teachos::x86_64::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 + 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>; + + /** + * @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::x86_64::io + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/io/port_io.hpp b/arch/x86_64/include/x86_64/io/port_io.hpp deleted file mode 100644 index 4cf0b65..0000000 --- a/arch/x86_64/include/x86_64/io/port_io.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP -#define TEACHOS_X86_64_IO_PORT_IO_HPP - -#include -#include -#include - -namespace teachos::x86_64::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 - 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>; - - /** - * @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::x86_64::io - -#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..4b4eac5 --- /dev/null +++ b/arch/x86_64/include/x86_64/vga/crtc.hpp @@ -0,0 +1,35 @@ +#ifndef TEACHOS_X86_64_VGA_IO_HPP +#define TEACHOS_X86_64_VGA_IO_HPP + +#include "x86_64/device_io/port_io.hpp" + +#include + +namespace teachos::x86_64::vga::crtc +{ + /** + * @brief The address port of the CRT Controller. + */ + using address = x86_64::io::port<0x3d4, 1>; + + /** + * @brief The data port of the CRT Controller. + */ + using data = x86_64::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 cursor_end = std::byte{0x0b}; + } // namespace registers + +} // namespace teachos::x86_64::vga::crtc + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/vga/io.hpp b/arch/x86_64/include/x86_64/vga/io.hpp deleted file mode 100644 index 4d99788..0000000 --- a/arch/x86_64/include/x86_64/vga/io.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_IO_HPP -#define TEACHOS_X86_64_VGA_IO_HPP - -#include "x86_64/io/port_io.hpp" - -#include - -namespace teachos::x86_64::vga::io -{ - namespace crtc - { - /** - * @brief The address port of the CRT Controller. - */ - using address_port = x86_64::io::port<0x3d4, 1>; - - /** - * @brief The data port of the CRT Controller. - */ - using data_port = x86_64::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 cursor_end = std::byte{0x0b}; - } // namespace registers - - }; // namespace crtc - -} // namespace teachos::x86_64::vga::io - -#endif \ No newline at end of file diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index dcfdb6b..5c94b84 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,7 +1,7 @@ #include "x86_64/vga/text.hpp" #include "x86_64/boot/boot.hpp" -#include "x86_64/vga/io.hpp" +#include "x86_64/vga/crtc.hpp" #include #include @@ -29,8 +29,8 @@ namespace teachos::x86_64::vga::text { auto cursor_disable_byte = std::byte{!enabled} << 5; - io::crtc::address_port::write(io::crtc::registers::cursor_start); - io::crtc::data_port::write(io::crtc::data_port::read() | cursor_disable_byte); + crtc::address::write(crtc::registers::cursor_start); + crtc::data::write(crtc::data::read() | cursor_disable_byte); } auto newline() -> void -- cgit v1.2.3 From 1b65136a11453fe7e89320dfe6170a0cd75e60dd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:33:10 +0000 Subject: x86_64: clean up hw details --- arch/x86_64/CMakeLists.txt | 4 ++ arch/x86_64/include/arch/boot/pointers.hpp | 15 ----- .../include/arch/kernel/cpu/control_register.hpp | 71 --------------------- arch/x86_64/include/arch/kernel/cpu/tlb.hpp | 27 -------- arch/x86_64/include/x86_64/cpu/registers.hpp | 72 ++++++++++++++++++++++ arch/x86_64/include/x86_64/memory/mmu.hpp | 27 ++++++++ arch/x86_64/src/cpu/registers.cpp | 64 +++++++++++++++++++ arch/x86_64/src/kernel/cpu/control_register.cpp | 66 -------------------- arch/x86_64/src/kernel/cpu/tlb.cpp | 16 ----- arch/x86_64/src/memory/mmu.cpp | 17 +++++ 10 files changed, 184 insertions(+), 195 deletions(-) delete mode 100644 arch/x86_64/include/arch/boot/pointers.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/tlb.hpp create mode 100644 arch/x86_64/include/x86_64/cpu/registers.hpp create mode 100644 arch/x86_64/include/x86_64/memory/mmu.hpp create mode 100644 arch/x86_64/src/cpu/registers.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/control_register.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/tlb.cpp create mode 100644 arch/x86_64/src/memory/mmu.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index ddc2d46..c585cbf 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -22,7 +22,11 @@ target_sources("x86_64" PRIVATE "src/boot/initialize_runtime.cpp" "src/boot/multiboot.s" + # CPU intrinsics + "src/cpu/registers.cpp" + # Memory management + "src/memory/mmu.cpp" "src/memory/region_allocator.cpp" # VGA text mode 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 - -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/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 - -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/kernel/cpu/tlb.hpp b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp deleted file mode 100644 index f3e58a6..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP - -#include "arch/memory/paging/virtual_page.hpp" - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @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; - - /** - * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. - * - * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because - * the system has to assume that the location of the level 4 page table moved. - */ - auto tlb_flush_all() -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP 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..607d559 --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -0,0 +1,72 @@ +#ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_REGISTERS_HPP + +#include + +namespace teachos::x86_64::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::x86_64::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/mmu.hpp b/arch/x86_64/include/x86_64/memory/mmu.hpp new file mode 100644 index 0000000..b03ffa2 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/mmu.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_X86_64_MEMORY_MMU_HPP +#define TEACHOS_X86_64_MEMORY_MMU_HPP + +#include "x86_64/memory/address.hpp" + +namespace teachos::x86_64::memory +{ + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + auto tlb_flush(linear_address address) -> void; + + /** + * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. + * + * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because + * the system has to assume that the location of the level 4 page table moved. + */ + auto tlb_flush_all() -> void; + +} // namespace teachos::x86_64::memory + +#endif \ No newline at end of file diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp new file mode 100644 index 0000000..7ade98d --- /dev/null +++ b/arch/x86_64/src/cpu/registers.cpp @@ -0,0 +1,64 @@ +#include "x86_64/cpu/registers.hpp" + +#include + +namespace teachos::x86_64::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::type>(flag) | cr0); + } +} // namespace teachos::x86_64::cpu 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 - -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::type>(flag) | cr0); - } -} // 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/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp new file mode 100644 index 0000000..31783fe --- /dev/null +++ b/arch/x86_64/src/memory/mmu.cpp @@ -0,0 +1,17 @@ +#include "x86_64/memory/mmu.hpp" + +#include "x86_64/cpu/registers.hpp" + +namespace teachos::x86_64::memory +{ + 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 current_value = cpu::read_control_register(cpu::control_register::cr3); + cpu::write_control_register(cpu::control_register::cr3, current_value); + } +} // namespace teachos::x86_64::memory -- cgit v1.2.3 From 2d3399ab6072acd85811a54fce8eff50628888b6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:35:34 +0000 Subject: x86_64: move files out of the way --- .../interrupt_descriptor_table/gate_descriptor.hpp | 69 ------- .../interrupt_descriptor_table/idt_flags.hpp | 81 -------- .../interrupt_descriptor_table.hpp | 24 --- .../interrupt_descriptor_table_pointer.hpp | 40 ---- .../interrupt_descriptor_table/ist_offset.hpp | 45 ----- .../segment_selector.hpp | 105 ----------- .../x86_64/include/arch/context_switching/main.hpp | 51 ----- .../segment_descriptor_table/access_byte.hpp | 104 ----------- .../segment_descriptor_table/gdt_flags.hpp | 93 ---------- .../global_descriptor_table.hpp | 37 ---- .../global_descriptor_table_pointer.hpp | 41 ---- .../segment_descriptor_base.hpp | 73 -------- .../segment_descriptor_extension.hpp | 74 -------- .../segment_descriptor_type.hpp | 27 --- .../task_state_segment.hpp | 32 ---- .../arch/context_switching/syscall/main.hpp | 88 --------- .../context_switching/syscall/syscall_enable.hpp | 18 -- .../context_switching/syscall/syscall_handler.hpp | 18 -- .../include/arch/exception_handling/assert.hpp | 17 -- .../include/arch/exception_handling/panic.hpp | 23 --- .../generic_interrupt_handler.hpp | 34 ---- arch/x86_64/include/arch/kernel/cpu/call.hpp | 30 --- arch/x86_64/include/arch/kernel/cpu/gdtr.hpp | 27 --- arch/x86_64/include/arch/kernel/cpu/idtr.hpp | 27 --- arch/x86_64/include/arch/kernel/cpu/if.hpp | 21 --- arch/x86_64/include/arch/kernel/cpu/msr.hpp | 64 ------- .../include/arch/kernel/cpu/segment_register.hpp | 97 ---------- arch/x86_64/include/arch/kernel/cpu/tr.hpp | 24 --- arch/x86_64/include/arch/kernel/halt.hpp | 13 -- arch/x86_64/include/arch/kernel/main.hpp | 13 -- .../arch/memory/allocator/area_frame_allocator.hpp | 67 ------- .../include/arch/memory/allocator/concept.hpp | 21 --- .../arch/memory/allocator/tiny_frame_allocator.hpp | 74 -------- .../include/arch/memory/heap/bump_allocator.hpp | 48 ----- .../arch/memory/heap/global_heap_allocator.hpp | 118 ------------ .../include/arch/memory/heap/heap_allocator.hpp | 45 ----- .../arch/memory/heap/linked_list_allocator.hpp | 120 ------------ .../include/arch/memory/heap/memory_block.hpp | 39 ---- .../arch/memory/heap/user_heap_allocator.hpp | 149 --------------- arch/x86_64/include/arch/memory/main.hpp | 30 --- .../arch/memory/multiboot/elf_symbols_section.hpp | 170 ----------------- .../include/arch/memory/multiboot/reader.hpp | 58 ------ .../arch/memory/paging/active_page_table.hpp | 206 --------------------- .../arch/memory/paging/inactive_page_table.hpp | 39 ---- .../include/arch/memory/paging/kernel_mapper.hpp | 180 ------------------ .../include/arch/memory/paging/page_entry.hpp | 121 ------------ .../include/arch/memory/paging/page_table.hpp | 157 ---------------- .../include/arch/memory/paging/temporary_page.hpp | 64 ------- .../include/arch/memory/paging/virtual_page.hpp | 91 --------- arch/x86_64/include/arch/user/main.hpp | 16 -- .../interrupt_descriptor_table/gate_descriptor.hpp | 69 +++++++ .../interrupt_descriptor_table/idt_flags.hpp | 81 ++++++++ .../interrupt_descriptor_table.hpp | 24 +++ .../interrupt_descriptor_table_pointer.hpp | 40 ++++ .../interrupt_descriptor_table/ist_offset.hpp | 45 +++++ .../segment_selector.hpp | 105 +++++++++++ .../pre/include/arch/context_switching/main.hpp | 51 +++++ .../segment_descriptor_table/access_byte.hpp | 104 +++++++++++ .../segment_descriptor_table/gdt_flags.hpp | 93 ++++++++++ .../global_descriptor_table.hpp | 37 ++++ .../global_descriptor_table_pointer.hpp | 41 ++++ .../segment_descriptor_base.hpp | 73 ++++++++ .../segment_descriptor_extension.hpp | 74 ++++++++ .../segment_descriptor_type.hpp | 27 +++ .../task_state_segment.hpp | 32 ++++ .../arch/context_switching/syscall/main.hpp | 88 +++++++++ .../context_switching/syscall/syscall_enable.hpp | 18 ++ .../context_switching/syscall/syscall_handler.hpp | 18 ++ .../pre/include/arch/exception_handling/assert.hpp | 17 ++ .../pre/include/arch/exception_handling/panic.hpp | 23 +++ .../generic_interrupt_handler.hpp | 34 ++++ arch/x86_64/pre/include/arch/kernel/cpu/call.hpp | 30 +++ arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp | 27 +++ arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp | 27 +++ arch/x86_64/pre/include/arch/kernel/cpu/if.hpp | 21 +++ arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp | 64 +++++++ .../include/arch/kernel/cpu/segment_register.hpp | 97 ++++++++++ arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp | 24 +++ arch/x86_64/pre/include/arch/kernel/halt.hpp | 13 ++ arch/x86_64/pre/include/arch/kernel/main.hpp | 13 ++ .../arch/memory/allocator/area_frame_allocator.hpp | 67 +++++++ .../pre/include/arch/memory/allocator/concept.hpp | 21 +++ .../arch/memory/allocator/tiny_frame_allocator.hpp | 74 ++++++++ .../include/arch/memory/heap/bump_allocator.hpp | 48 +++++ .../arch/memory/heap/global_heap_allocator.hpp | 118 ++++++++++++ .../include/arch/memory/heap/heap_allocator.hpp | 45 +++++ .../arch/memory/heap/linked_list_allocator.hpp | 120 ++++++++++++ .../pre/include/arch/memory/heap/memory_block.hpp | 39 ++++ .../arch/memory/heap/user_heap_allocator.hpp | 149 +++++++++++++++ arch/x86_64/pre/include/arch/memory/main.hpp | 30 +++ .../arch/memory/multiboot/elf_symbols_section.hpp | 170 +++++++++++++++++ .../pre/include/arch/memory/multiboot/reader.hpp | 58 ++++++ .../arch/memory/paging/active_page_table.hpp | 206 +++++++++++++++++++++ .../arch/memory/paging/inactive_page_table.hpp | 39 ++++ .../include/arch/memory/paging/kernel_mapper.hpp | 180 ++++++++++++++++++ .../pre/include/arch/memory/paging/page_entry.hpp | 121 ++++++++++++ .../pre/include/arch/memory/paging/page_table.hpp | 157 ++++++++++++++++ .../include/arch/memory/paging/temporary_page.hpp | 64 +++++++ .../include/arch/memory/paging/virtual_page.hpp | 91 +++++++++ arch/x86_64/pre/include/arch/user/main.hpp | 16 ++ .../interrupt_descriptor_table/gate_descriptor.cpp | 24 +++ .../interrupt_descriptor_table/idt_flags.cpp | 17 ++ .../interrupt_descriptor_table.cpp | 53 ++++++ .../interrupt_descriptor_table_pointer.cpp | 13 ++ .../interrupt_descriptor_table/ist_offset.cpp | 10 + .../segment_selector.cpp | 15 ++ arch/x86_64/pre/src/context_switching/main.cpp | 63 +++++++ .../segment_descriptor_table/access_byte.cpp | 17 ++ .../segment_descriptor_table/gdt_flags.cpp | 20 ++ .../global_descriptor_table.cpp | 109 +++++++++++ .../global_descriptor_table_pointer.cpp | 11 ++ .../segment_descriptor_base.cpp | 38 ++++ .../segment_descriptor_extension.cpp | 24 +++ .../pre/src/context_switching/syscall/main.cpp | 35 ++++ .../context_switching/syscall/syscall_enable.cpp | 32 ++++ .../context_switching/syscall/syscall_handler.cpp | 118 ++++++++++++ arch/x86_64/pre/src/exception_handling/abort.cpp | 15 ++ arch/x86_64/pre/src/exception_handling/assert.cpp | 15 ++ arch/x86_64/pre/src/exception_handling/panic.cpp | 22 +++ .../pre/src/exception_handling/pure_virtual.cpp | 6 + .../generic_interrupt_handler.cpp | 13 ++ arch/x86_64/pre/src/kernel/cpu/call.cpp | 9 + arch/x86_64/pre/src/kernel/cpu/gdtr.cpp | 19 ++ arch/x86_64/pre/src/kernel/cpu/idtr.cpp | 18 ++ arch/x86_64/pre/src/kernel/cpu/if.cpp | 7 + arch/x86_64/pre/src/kernel/cpu/msr.cpp | 31 ++++ .../x86_64/pre/src/kernel/cpu/segment_register.cpp | 98 ++++++++++ arch/x86_64/pre/src/kernel/cpu/tr.cpp | 16 ++ arch/x86_64/pre/src/kernel/main.cpp | 71 +++++++ .../src/memory/allocator/area_frame_allocator.cpp | 85 +++++++++ .../src/memory/allocator/tiny_frame_allocator.cpp | 34 ++++ arch/x86_64/pre/src/memory/heap/bump_allocator.cpp | 54 ++++++ .../pre/src/memory/heap/global_heap_allocator.cpp | 135 ++++++++++++++ .../pre/src/memory/heap/linked_list_allocator.cpp | 177 ++++++++++++++++++ arch/x86_64/pre/src/memory/heap/memory_block.cpp | 15 ++ .../pre/src/memory/heap/user_heap_allocator.cpp | 200 ++++++++++++++++++++ arch/x86_64/pre/src/memory/main.cpp | 77 ++++++++ .../src/memory/multiboot/elf_symbols_section.cpp | 13 ++ arch/x86_64/pre/src/memory/multiboot/reader.cpp | 135 ++++++++++++++ .../pre/src/memory/paging/active_page_table.cpp | 98 ++++++++++ .../pre/src/memory/paging/inactive_page_table.cpp | 20 ++ arch/x86_64/pre/src/memory/paging/page_entry.cpp | 63 +++++++ arch/x86_64/pre/src/memory/paging/page_table.cpp | 128 +++++++++++++ .../pre/src/memory/paging/temporary_page.cpp | 29 +++ arch/x86_64/pre/src/memory/paging/virtual_page.cpp | 33 ++++ arch/x86_64/pre/src/user/main.cpp | 35 ++++ .../interrupt_descriptor_table/gate_descriptor.cpp | 24 --- .../interrupt_descriptor_table/idt_flags.cpp | 17 -- .../interrupt_descriptor_table.cpp | 53 ------ .../interrupt_descriptor_table_pointer.cpp | 13 -- .../interrupt_descriptor_table/ist_offset.cpp | 10 - .../segment_selector.cpp | 15 -- arch/x86_64/src/context_switching/main.cpp | 63 ------- .../segment_descriptor_table/access_byte.cpp | 17 -- .../segment_descriptor_table/gdt_flags.cpp | 20 -- .../global_descriptor_table.cpp | 109 ----------- .../global_descriptor_table_pointer.cpp | 11 -- .../segment_descriptor_base.cpp | 38 ---- .../segment_descriptor_extension.cpp | 24 --- arch/x86_64/src/context_switching/syscall/main.cpp | 35 ---- .../context_switching/syscall/syscall_enable.cpp | 32 ---- .../context_switching/syscall/syscall_handler.cpp | 118 ------------ arch/x86_64/src/exception_handling/abort.cpp | 15 -- arch/x86_64/src/exception_handling/assert.cpp | 15 -- arch/x86_64/src/exception_handling/panic.cpp | 22 --- .../x86_64/src/exception_handling/pure_virtual.cpp | 6 - .../generic_interrupt_handler.cpp | 13 -- arch/x86_64/src/kernel/cpu/call.cpp | 9 - arch/x86_64/src/kernel/cpu/gdtr.cpp | 19 -- arch/x86_64/src/kernel/cpu/idtr.cpp | 18 -- arch/x86_64/src/kernel/cpu/if.cpp | 7 - arch/x86_64/src/kernel/cpu/msr.cpp | 31 ---- arch/x86_64/src/kernel/cpu/segment_register.cpp | 98 ---------- arch/x86_64/src/kernel/cpu/tr.cpp | 16 -- arch/x86_64/src/kernel/main.cpp | 71 ------- .../src/memory/allocator/area_frame_allocator.cpp | 85 --------- .../src/memory/allocator/tiny_frame_allocator.cpp | 34 ---- arch/x86_64/src/memory/heap/bump_allocator.cpp | 54 ------ .../src/memory/heap/global_heap_allocator.cpp | 135 -------------- .../src/memory/heap/linked_list_allocator.cpp | 177 ------------------ arch/x86_64/src/memory/heap/memory_block.cpp | 15 -- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 200 -------------------- arch/x86_64/src/memory/main.cpp | 77 -------- .../src/memory/multiboot/elf_symbols_section.cpp | 13 -- arch/x86_64/src/memory/multiboot/reader.cpp | 135 -------------- .../x86_64/src/memory/paging/active_page_table.cpp | 98 ---------- .../src/memory/paging/inactive_page_table.cpp | 20 -- arch/x86_64/src/memory/paging/page_entry.cpp | 63 ------- arch/x86_64/src/memory/paging/page_table.cpp | 128 ------------- arch/x86_64/src/memory/paging/temporary_page.cpp | 29 --- arch/x86_64/src/memory/paging/virtual_page.cpp | 33 ---- arch/x86_64/src/user/main.cpp | 35 ---- 192 files changed, 5493 insertions(+), 5493 deletions(-) delete mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/main.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/syscall/main.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp delete mode 100644 arch/x86_64/include/arch/exception_handling/assert.hpp delete mode 100644 arch/x86_64/include/arch/exception_handling/panic.hpp delete mode 100644 arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/call.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/gdtr.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/idtr.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/if.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/msr.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/segment_register.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/tr.hpp delete mode 100644 arch/x86_64/include/arch/kernel/halt.hpp delete mode 100644 arch/x86_64/include/arch/kernel/main.hpp delete mode 100644 arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/allocator/concept.hpp delete mode 100644 arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/bump_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/heap_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/memory_block.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/main.hpp delete mode 100644 arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp delete mode 100644 arch/x86_64/include/arch/memory/multiboot/reader.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/active_page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/page_entry.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/temporary_page.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/virtual_page.hpp delete mode 100644 arch/x86_64/include/arch/user/main.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/main.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/access_byte.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp create mode 100644 arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp create mode 100644 arch/x86_64/pre/include/arch/exception_handling/assert.hpp create mode 100644 arch/x86_64/pre/include/arch/exception_handling/panic.hpp create mode 100644 arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/call.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/if.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/halt.hpp create mode 100644 arch/x86_64/pre/include/arch/kernel/main.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/allocator/area_frame_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/allocator/concept.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/heap/bump_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/main.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/multiboot/elf_symbols_section.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/inactive_page_table.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/page_entry.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/page_table.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/temporary_page.hpp create mode 100644 arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp create mode 100644 arch/x86_64/pre/include/arch/user/main.hpp create mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp create mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp create mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp create mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp create mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp create mode 100644 arch/x86_64/pre/src/context_switching/main.cpp create mode 100644 arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp create mode 100644 arch/x86_64/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp create mode 100644 arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp create mode 100644 arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp create mode 100644 arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp create mode 100644 arch/x86_64/pre/src/context_switching/syscall/main.cpp create mode 100644 arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp create mode 100644 arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp create mode 100644 arch/x86_64/pre/src/exception_handling/abort.cpp create mode 100644 arch/x86_64/pre/src/exception_handling/assert.cpp create mode 100644 arch/x86_64/pre/src/exception_handling/panic.cpp create mode 100644 arch/x86_64/pre/src/exception_handling/pure_virtual.cpp create mode 100644 arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/call.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/gdtr.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/idtr.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/if.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/msr.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/segment_register.cpp create mode 100644 arch/x86_64/pre/src/kernel/cpu/tr.cpp create mode 100644 arch/x86_64/pre/src/kernel/main.cpp create mode 100644 arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/bump_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/memory_block.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/main.cpp create mode 100644 arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp create mode 100644 arch/x86_64/pre/src/memory/multiboot/reader.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/active_page_table.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/page_entry.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/page_table.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/temporary_page.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/virtual_page.cpp create mode 100644 arch/x86_64/pre/src/user/main.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp delete mode 100644 arch/x86_64/src/context_switching/main.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp delete mode 100644 arch/x86_64/src/context_switching/syscall/main.cpp delete mode 100644 arch/x86_64/src/context_switching/syscall/syscall_enable.cpp delete mode 100644 arch/x86_64/src/context_switching/syscall/syscall_handler.cpp delete mode 100644 arch/x86_64/src/exception_handling/abort.cpp delete mode 100644 arch/x86_64/src/exception_handling/assert.cpp delete mode 100644 arch/x86_64/src/exception_handling/panic.cpp delete mode 100644 arch/x86_64/src/exception_handling/pure_virtual.cpp delete mode 100644 arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/call.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/gdtr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/idtr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/if.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/msr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/segment_register.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/tr.cpp delete mode 100644 arch/x86_64/src/kernel/main.cpp delete mode 100644 arch/x86_64/src/memory/allocator/area_frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/bump_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/global_heap_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/linked_list_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/memory_block.cpp delete mode 100644 arch/x86_64/src/memory/heap/user_heap_allocator.cpp delete mode 100644 arch/x86_64/src/memory/main.cpp delete mode 100644 arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp delete mode 100644 arch/x86_64/src/memory/multiboot/reader.cpp delete mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/inactive_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_entry.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/temporary_page.cpp delete mode 100644 arch/x86_64/src/memory/paging/virtual_page.cpp delete mode 100644 arch/x86_64/src/user/main.cpp diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp deleted file mode 100644 index 07110c8..0000000 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP - -#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" -#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - __extension__ typedef __int128 int128_t; - __extension__ typedef unsigned __int128 uint128_t; - - /** - * @brief Defines helper function for all states and the actual data the gate descriptor can have. - */ - struct [[gnu::packed]] gate_descriptor - { - /** - * @brief Default Constructor. - */ - gate_descriptor() = default; - - /** - * @brief Constructor. - * - * @note Created gate descriptor copies the given bytes into these components ending with a 32 bit reserved - * field that has to be used, because the 64-bit gate descriptor needs to be big enough for two 32-bit gate - * descriptor. - * - 16 bit Segment Selector - * - 3 bit Interrupt Stack Table Offset - * - 8 bit Type and Flags - * - 64 bit Offset - * - * @param flags Copies the bits set from the given data into the individual components of a gate - * descriptor. - */ - explicit gate_descriptor(uint128_t flags); - - /** - * @brief Constructor. - * - * @param selector, ist, flags, offset Copies the bits set from the given data into the individual components of - * a gate descriptor. - */ - gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset); - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(gate_descriptor const & other) const -> bool = default; - - private: - // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _offset_1 = {}; ///< Lower 16 bits of handler function address (0 - 15) - segment_selector _selector = {}; ///< Segment selector (16 - 31) - ist_offset _ist = {}; ///< Interrupt Stack Table offset (32 - 39) - idt_flags _flags = {}; ///< Gate Type and Flags (40 - 47) - uint64_t _offset_2 : 48 = {}; ///< Upper 48 bits of handler function address (48 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp deleted file mode 100644 index 5104c36..0000000 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp +++ /dev/null @@ -1,81 +0,0 @@ - -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Defines helper function for all states that the access byte field of a segment descriptor can - * have. - */ - struct [[gnu::packed]] idt_flags - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - INTERRUPT_GATE = 0b01110, ///< The actual type of gate segment is a interrupt gate. - TRAP_GATE = 0b01111, ///< The actual type of gate segment is a trap gate. - DESCRIPTOR_LEVEL_KERNEL = - 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. - DESCRIPTOR_LEVEL_ADMIN = - 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_PRIVILEGED_USER = - 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. - PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. - }; - - /** - * @brief Default Constructor. - */ - idt_flags() = default; - - /** - * @brief Constructor. - * - * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used - * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags - * are enabled or not using contains_flags method. - */ - idt_flags(uint8_t flags); - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<8U> other) const -> bool; - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(idt_flags const & other) const -> bool = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<8U> other) -> void; - - private: - uint8_t _flags = {}; ///< Underlying bits used to read the flags from. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp deleted file mode 100644 index b388e0e..0000000 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Updates the IDTR with the created interrupt descriptor table. If it has not been created yet this - * method will create it. - */ - auto update_interrupt_descriptor_table_register() -> void; - - /** - * @brief Creates the interrupt descriptor table, with the minimum required configuration. If this method is called - * more than once, the previously created instance is returned instead. - * - * @return Reference to the created interrupt_descriptor_table. - */ - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &; - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp deleted file mode 100644 index 7fe933b..0000000 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP - -#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" -#include "arch/stl/vector.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - using interrupt_descriptor_table = stl::vector; - - /** - * @brief Represents a pointer to the Interrupt Descriptor Table (IDT). - * - * This structure is used to store the base address and length of the IDT. - */ - struct [[gnu::packed]] interrupt_descriptor_table_pointer - { - /** - * @brief Default constructor. - */ - interrupt_descriptor_table_pointer() = default; - - /** - * @brief Constructor. - */ - interrupt_descriptor_table_pointer(uint16_t table_length, gate_descriptor * address); - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(interrupt_descriptor_table_pointer const & other) const -> std::strong_ordering = default; - - private: - uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - gate_descriptor * address = {}; ///< Non-owning pointer to the IDT base address. - }; - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp deleted file mode 100644 index e45bcf4..0000000 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Defines helper function for all states that the interrupt stack table offset field of a gate descriptor can - * have. Is automatically increased to one byte in size, to include the following 5 reserved bits in the gate - * descriptor. - */ - struct [[gnu::packed]] ist_offset - { - /** - * @brief Default Constructor. - */ - ist_offset() = default; - - /** - * @brief Constructor. - * - * @param offset Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, whereas 1 - 7 - * mean we switch to the n-th stack in the Interrupt Stack Table, contained in the TSS if the gate descriptor that - * contains this field is called. - */ - ist_offset(uint8_t offset); - - /** - * @brief Allows to compare the underlying set bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(ist_offset const & other) const -> bool = default; - - private: - uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, - ///< whereas 1 - 7 mean we switch to the n-th stack in the Interrupt Stack Table, contained - ///< in the TSS if the gate descriptor that contains this field is called. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp deleted file mode 100644 index 2a7704e..0000000 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Represents a segment selector in the x86_64 architecture, which points to a valid code segment in the global - * descriptor table. - * - * A segment selector is a 16-bit identifier used to select a segment descriptor - * from the Global Descriptor Table (GDT) or the Local Descriptor Table (LDT). - * It contains an index, a table indicator (TI), and a requested privilege level (RPL). - */ - struct [[gnu::packed]] segment_selector - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - REQUEST_LEVEL_KERNEL = - 0U << 0U, ///< Highest privileged level used by the kernel to allow for full access of resources. - REQUEST_LEVEL_ADMIN = - 1U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - REQUEST_LEVEL_PRIVILEGED_USER = - 2U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - REQUEST_LEVEL_USER = 3U << 0U, ///< Restricts access to only application and their specific memory. - LOCAL_DESCRIPTOR_TABLE = 1U << 2U, ///< Wheter the index referes to an entry in the local or global descriptor - ///< table. If enabled the index points to a local descriptor table, if it is - ///< cleared it referes to a global descriptor table instead. - }; - - /** - * @brief Default constructor. - */ - segment_selector() = default; - - /** - * @brief Constructor. - * - * @param index Index into the local or global descriptor table. Processor multiplies the index value by 8 (number - * of bytes in 32-bit segment descriptor) and adds the result to the base GDT or LDT address. - * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to - * allow for direct integer conversion. - */ - constexpr segment_selector(uint16_t index, uint8_t flags) - : _flags(flags) - , _index(index) - { - // Nothing to do. - } - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<3U> other) const -> bool; - - /** - * @brief Gets the index into the global descriptor table or the local descriptor table this segment selector is - * pointing too. - * - * @return Underlying value of the index field, bit 3 - 16. - */ - [[gnu::section(".user_text")]] - auto get_index() const -> uint16_t; - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<3U> other) -> void; - - /** - * @brief Cast the underlying data into a combined 16-bit form, that contains all data. - * - * @return Underlying value combined into it's full size. - */ - operator uint16_t() const; - - 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. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/include/arch/context_switching/main.hpp deleted file mode 100644 index f8477ea..0000000 --- a/arch/x86_64/include/arch/context_switching/main.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" - -namespace teachos::arch::context_switching -{ - /** - * @brief Contains the references to the tables required for context switching - */ - struct descriptor_tables - { - segment_descriptor_table::global_descriptor_table & gdt; ///< Reference to the global descriptor table. - interrupt_descriptor_table::interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. - }; - - /** - * @brief Creates the Interrupt Descriptor Table and Global Descriptor Table as a static variable the first time this - * method is called and update IDTR and GDTR registers values. - * - * @note Subsequent calls after the first one, will simply return the previously created tables, but not update the - * registers again. - * - * @return References to the statically created Interrupt Descriptor and Global Descriptor Table. - */ - auto initialize_descriptor_tables() -> descriptor_tables; - - /** - * @brief Switches from the current Kernel Mode (Level 0) to User Mode (Level 3). Will simply use predefined Segment - * Selectors for the User Data and User Code Segment, which are Index 3 and 4 in the GDT respectively. - */ - auto switch_to_user_mode() -> void; - - /** - * @brief Switches from the current Code and Data Segment to the given Code and Data Segment. - * - * @note This method will additionally call initialize_descriptor_tables, to ensure the GDTR and IDTR have been setup - * correctly before attempting to switch the context. This switch is achieved using a far return, which will once - * executed call the given void function. - * - * @param data_segment Data Segment that the SS, DS; ES, FS and GS register will be set too. - * @param code_segment Code Segment that the CS register will be set too. - * @param return_function Function that will be called once the switch has been achieved. - */ - auto switch_context(interrupt_descriptor_table::segment_selector data_segment, - interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void; - -} // namespace teachos::arch::context_switching - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp deleted file mode 100644 index 7450330..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp +++ /dev/null @@ -1,104 +0,0 @@ - -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP - -#include -#include - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - /** - * @brief Defines helper function for all states that the access byte field of a segment descriptor can - * have. - */ - struct [[gnu::packed]] access_byte - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - ACCESSED = - 1U - << 0U, ///< Whether the segment has been accessed since the last time the operating system has cleared the - ///< flag. If enabled it has been accessed, otherwise it has not been accessed since the last clear. - WRITABLE = 1U << 1U, ///< Indicates if the data segment is writable or not. If enabled the code segment allows - ///< read and write access, otherwise only read access is possible. - READABLE = 1U << 1U, ///< Indicates if the code segment is readable or not. If enabled the code segment allows - ///< read and execute access, otherwise only executable access is possible. - CONFORMING = - 1U << 2U, ///< Indicates if the code is allowed to be executed by different access levels - ///< (higher or lower) in code segments. If enabled the code segment allows access, otherwise - ///< access from different privilege levels with throw a General-Protectione exception. - EXPAND_DOWN = 1U << 2U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the - ///< data segment expands downwards, otherwise it expands upwards. - CODE_SEGMENT = 1U << 3U, ///< Further defines the actual type of the segment. If enabled this segment is a code - ///< segment, otherwise its a data segment. - LOCAL_DESCRIPTOR_TABLE = 2, ///< The actual type of sytem segment is a local descriptor table. - TASK_STATE_SEGMENT_AVAILABLE = - 9, ///< The actual type of sytem segment is a task state segment that is still available. - TASK_STATE_SEGMENT_BUSY = 11, ///< The actual type of sytem segment is a task state segment that is currently in - ///< use and therefore busy. - CALL_GATE = 11, ///< The actual type of sytem segment is a call gate. - INTERRUPT_GATE = 14, ///< The actual type of sytem segment is a interrupt gate. - TRAP_GATE = 15, ///< The actual type of sytem segment is a trap gate. - CODE_OR_DATA_SEGMENT = 1U << 4U, ///< Defines a system segment (if 0) or a code/data segment (if 1). - DESCRIPTOR_LEVEL_KERNEL = - 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. - DESCRIPTOR_LEVEL_ADMIN = - 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_PRIVILEGED_USER = - 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. - PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. - }; - - /** - * @brief Default Constructor. - */ - access_byte() = default; - - /** - * @brief Constructor. - * - * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used - * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags - * are enabled or not using contains_flags method. - */ - access_byte(uint8_t flags); - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<8U> other) const -> bool; - - /** - * @brief Allows to compare the underlying data of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying data of both types is the same. - */ - auto operator==(access_byte const & other) const -> bool = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<8U> other) -> void; - - private: - uint8_t _flags = {}; ///< Underlying bits used to read the flags from. - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp deleted file mode 100644 index e24b988..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GDT_FLAGS_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GDT_FLAGS_HPP - -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" - -#include - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - /** - * @brief Defines helper function for all states that the flags field of a segment descriptor can - * have. - */ - struct [[gnu::packed]] gdt_flags - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - LONG_MODE = 1U << 1U, ///< Defines in IA-32e mode (64-bit code and 32-bit compatability mode) if the segment - ///< contains 64-bit code. Otherwise this bit should always be 0. Enable if instructions - ///< are executed in 64-bit code, otherwise they are executed in compatability 32-bit mode. - ///< If this bit is set the 3rd bit needs to be clear (0). - UPPER_BOUND = 1U << 2U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 4 - ///< GiB, 4 KiB otherwise. - STACK_POINTER_SIZE = 1U << 2U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for - ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. - DEFAULT_LENGTH = 1U << 2U, ///< Indicates the default length for code segments with effective addresses and - ///< operands. Enable for 32 bit, 16 bit otherwise. - GRANULARITY = 1U << 3U, ///< Indicates the size the Limit value in the segment descriptor is scaled by 1 Byte - ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. - }; - - /** - * @brief Default Constructor. - */ - gdt_flags() = default; - - /** - * @brief Constructor. - * - * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to - * allow for direct integer conversion. This value is saved and can later be used to check whether certain flags are - * enabled or not using contains_flags method. - * @param limit Does not necessarily make sense in the gdt flags type, but because the flags alone are only 4 bit - * the type would still require the space for a complete bit. Therefore the 4 bit segment limit field before the - * flags field is included in this type to ensure we actually contain 8 bit of data. - */ - gdt_flags(uint8_t flags, std::bitset<20U> limit); - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<4U> other) const -> bool; - - /** - * @brief Get part of the segment limit that is saved in the gdt flags. This does not necessarily make sense in this - * object, but it has to be included here because a struct can not be smaller than a full byte. Therefore we include - * the 4 bit segment limit field so that it results in a compelte byte with the addtional 4 bit of gdt flags. - * - * @return 4-bit limit segment - */ - auto get_limit() const -> std::bitset<4U>; - - /** - * @brief Allows to compare the underlying set bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(gdt_flags const & other) const -> bool = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<4U> other) -> void; - - private: - uint8_t _limit_2 : 4 = {}; ///< Second part of the limit field. - uint8_t _flags : 4 = {}; ///< Underlying bits used to read the flags from. - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp deleted file mode 100644 index 44f2692..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP - -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" -#include "arch/context_switching/segment_descriptor_table/task_state_segment.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - /** - * @brief Creates the global descriptor table, with the minimum required configuration. If this method is called more - * than once, the previously created instance is returned instead. - * - * @return Reference to the created global_descriptor_table. - */ - auto get_or_create_gdt() -> global_descriptor_table &; - - /** - * @brief Updates the GDTR with the created global descriptor table. If it has not been created yet this - * method will create it. - * - * @note This method will only set the GDTR, but for the processor to actually register the change a far jump - * has to be executed. This also has to be done before updating the TR. - */ - auto update_gdtr() -> void; - - /** - * @brief Updates the TR with the created task state segment. If it has not been created yet this - * method will create it. - * - * @note This method should only be called after update_gdtr() and a far jump has been - * executed. Because before that trying to access the segment will cause an exception. - */ - auto update_tss_register() -> void; - -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp deleted file mode 100644 index 292ff70..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP - -#include "arch/stl/vector.hpp" - -#include - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - using global_descriptor_table = stl::vector; - - /** - * @brief Represents a pointer to the Global Descriptor Table (GDT). - * - * This structure is used to store the base address and length of the GDT. - * It is used when loading or modifying the GDT during context switching. - */ - struct [[gnu::packed]] global_descriptor_table_pointer - { - /** - * @brief Default constructor. - */ - global_descriptor_table_pointer() = default; - - /** - * @brief Constructor. - */ - global_descriptor_table_pointer(uint16_t table_length, uint64_t * address); - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(global_descriptor_table_pointer const & other) const -> std::strong_ordering = default; - - private: - uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - uint64_t * address = {}; ///< Non-owning pointer to the GDT base address. - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp deleted file mode 100644 index 933fb4d..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_BASE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_BASE_HPP - -#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" -#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - /** - * @brief Defines helper function for all states and the actual data the segment descriptor can have. - */ - struct [[gnu::packed]] segment_descriptor_base - { - /** - * @brief Default Constructor. - */ - segment_descriptor_base() = default; - - /** - * @brief Constructor. - * - * @note Created segment descriptor copies the given bytes into these components requiring the space of one - * segment descriptor entry in the global descriptor table being 64-bit. - * - 8 bit Access Type - * - 4 bit Flags - * - 32 bit Base Address - * - 20 bit Limit - * - * @param flags Copies the bits set from the given data into the individual components of a segment - * descriptor. - */ - explicit segment_descriptor_base(uint64_t flags); - - /** - * @brief Constructor. - * - * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of - * a segment descriptor. - */ - segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, std::bitset<20U> limit); - - /** - * @brief Calculates the underlying segment type that this segement descriptor is describing. - */ - auto get_segment_type() const -> segment_descriptor_type; - - /** - * @brief Cast the underlying data into a combined 64-bit form, that contains all data. - * - * @return Underlying value combined into it's full size. - */ - operator uint64_t() const; - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(segment_descriptor_base const & other) const -> bool = default; - - private: - // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _limit_1 = {}; ///< First part of the limit field (0 - 15) - uint32_t _base_1 : 24 = {}; ///< First part of the base field (16 - 39) - access_byte _access = {}; ///< Access byte field (40 - 47) - gdt_flags _flag = {}; ///< Second part of the limit field + Flags field (48 - 55) - uint8_t _base_2 = {}; ///< Second part of the base field (56 - 63) - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp deleted file mode 100644 index 40bcc8a..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP - -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - __extension__ typedef __int128 int128_t; - __extension__ typedef unsigned __int128 uint128_t; - - /** - * @brief Defines helper function for all states and the actual data the segment descriptor can have. - */ - struct [[gnu::packed]] segment_descriptor_extension - { - /** - * @brief Default Constructor. - */ - segment_descriptor_extension() = default; - - /** - * @brief Constructor. - * - * @note Created segment descriptor copies the given bytes into these components requiring the space of two - * segment descriptor entry in the global descriptor table being 128-bit. Ending with a 32 bit reserved - * field that has to be used, because the segment descriptor needs to be big enough for two segment - * descriptor entries. - * - 8 bit Access Type - * - 4 bit Flags - * - 64 bit Base Address - * - 20 bit Limit - * - * @param flags Copies the bits set from the given data into the individual components of a segment - * descriptor. - */ - explicit segment_descriptor_extension(uint128_t flags); - - /** - * @brief Constructor. - * - * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of - * a segment descriptor. - */ - segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit); - - /** - * @brief Returns the underlying base segment descriptor, being the first part of the segment descriptor consisting - * of two entries in the global descriptor table. - */ - auto get_first_gdt_entry() const -> segment_descriptor_base; - - /** - * @brief Returns the underlying extension to the segment descriptor, being the second part of the segment - * descriptor consiting of two entries in the global descriptor table. - */ - auto get_second_gdt_entry() const -> uint64_t; - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(segment_descriptor_extension const & other) const -> bool = default; - - private: - // The order in private variables starts for the first variable being the rightmost bit. - segment_descriptor_base _base = {}; ///< Base Segment Descriptor representing single entry in GDT (0 - 63) - uint32_t _base_3 = {}; ///< Third part of the base field (63 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp deleted file mode 100644 index 8770b81..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP - -#include - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - /** - * @brief Possible overlying types of the segment descriptor. Allowing to discern between the major types, which - * result in different handling of the actual data contained in the descriptor. - */ - enum class segment_descriptor_type : uint8_t - { - SYSTEM_SEGMENT, ///< The segment is of type system, is distinguished by the Descriptor Type field in the Access - ///< Byte. Can be further distinguised to specific system segment types using the Type Field in the - ///< Access Byte. - DATA_SEGMENT, ///< The segment is of type data, is is distinguished by the Descriptor Type field in the Access - ///< Byte and the first bit of the Type Field in the Access Byte. Can be further distinguised to - ///< specific data segment types using the the remaining bits in the Type Field in the Access Byte. - CODE_SEGMENT, ///< The segment is of type code, is is distinguished by the Descriptor Type field in - ///< the Access Byte and the first bit of the Type Field in the Access Byte. Can be - ///< further distinguised to specific data segment types using the the remaining bits in - ///< the Type Field in the Access Byte. - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp deleted file mode 100644 index d4aa5e8..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP - -#include - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - /** - * @brief 64-bit task state segment - */ - struct [[gnu::packed]] task_state_segment - { - private: - uint32_t : 32; - uint64_t rsp0 = {}; - uint64_t rsp1 = {}; - uint64_t rsp2 = {}; - uint64_t : 64; - uint64_t ist1 = {}; - uint64_t ist2 = {}; - uint64_t ist3 = {}; - uint64_t ist4 = {}; - uint64_t ist5 = {}; - uint64_t ist6 = {}; - uint64_t ist7 = {}; - uint64_t : 64; - uint16_t : 16; - uint16_t io_map_base_address = {}; - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_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/include/arch/context_switching/syscall/main.hpp deleted file mode 100644 index 59adc13..0000000 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP - -#include - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Possible syscall implementation that should actually be called. - * - * @note Attempts to reflect the Linux interface partially. See https://filippo.io/linux-syscall-table/ for more - * information. - */ - enum class type : uint64_t - { - WRITE = 1U, ///< Loads the arg_0 parameter as an address pointing to a const char array, which will then be printed - ///< onto the VGA buffer screen. - EXPAND_HEAP = 2U, /// Expands the User Heap by additonally mapping 100 KiB of virtual page memory. Ignores the - /// parameters and uses them as out parameters instead, where arg_0 is the start of the newly - /// mapped heap area and arg_1 is the size of the entire area. Can be less than 100 KiB if less - /// space remains. - ASSERT = 3U, /// Loads the arg_0 parameter as a boolean which needs to be true or it will print the message in - /// arg_1 parameter onto the VGA buffer screen, keep it as a nullptr if it shouldn't print anything - /// and then it halts the further execution of the application. - }; - - /** - * @brief Possible error codes that can be returned by the different syscall methods called depending on the type - * enum. - */ - enum class error : uint8_t - { - OK = 0U, ///< No error occured in syscall. - OUT_OF_MEMORY = 1U, ///< Expanding heap failed because we have run out of mappable virtual address space. - }; - - /** - * @brief Allows to convert the error enum type into a boolean directly. Where any code besides 0 being no error, will - * return true. The remaining errors return true. - * - * @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; } - - /** - * @brief Maximum amount of arguments that can be passed to a syscall. Default value is 0 and arguments are only ever - * used depending on the actual enum type and if the method requires thoose parameters. - */ - struct arguments - { - uint64_t arg_0{}; ///< First optional paramter to the syscall representing the RDI register. - uint64_t arg_1{}; ///< Second optional paramter to the syscall representing the RSI register. - uint64_t arg_2{}; ///< Third optional paramter to the syscall representing the RDX register. - uint64_t arg_3{}; ///< Fourth optional paramter to the syscall representing the R10 register. - uint64_t arg_4{}; ///< Fifth optional paramter to the syscall representing the R8 register. - uint64_t arg_5{}; ///< Sixth optional paramter to the syscall representing the R9 register. - }; - - /** - * @brief Response of a systemcall always containin an error code, signaling if the syscall even succeeded or not. - * Additionally it may contain up to 6 return values in the values struct. - */ - struct response - { - error error_code; ///< Error code returned by the syscall. If it failed all the values will be 0. - arguments values = {}; ///< Optional return values of the syscall implementation. - }; - - /** - * @brief Calls the method associated with the given syscall number and passes the given optional arguments to it, - * over the RDI, RSI, RDX, R10, R8 and R9 register. - * - * @param syscall_number Syscall method that should be called. See enum values in type for possible implemented - * methods. - * @param args Optional arguments passable to the different syscall methods, called depending on the syscall_number. - * Not passing the required parameters to the method, will result in passing 0 instead, which might make the fail or - * not function correctly. - * @return The syscall implementation always returns a bool-convertable error code converting to true if the syscall - * failed or false if it didn't. Additionally it might pase additional values besides the error code, they will be set - * in the arguments struct. So the value can be read and used for further processing. - */ - [[gnu::section(".user_text")]] - auto syscall(type syscall_number, arguments args = {}) -> response; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP diff --git a/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp b/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp deleted file mode 100644 index 8cb468a..0000000 --- a/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Enables and sets up internal CPU registers to allow for syscall to function correctly and switch context - * temporarily back to the kernel level. - * - * @note Configures the Model Specific Register required by syscall (LSTAR, FMASK, STAR) with the correct values so - * that the syscall_handler is called and sets the System Call Extension bit on the EFER flags to allow for syscall - * to be used. - */ - auto enable_syscall() -> void; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp b/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp deleted file mode 100644 index 2e7bcd1..0000000 --- a/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP - -#include - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Handler for SYSCALL instruction. Calls a specific implementation based - * on the register RAX. - * - * @return Returns with LEAVE, SYSRETQ - */ - auto syscall_handler() -> void; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp deleted file mode 100644 index 1286768..0000000 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP -#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP - -namespace teachos::arch::exception_handling -{ - /** - * @brief Assert a condition to be true, if not do not continue - * execution of the code and print the given message to screen. - * - * @param condition Condition we want to be true or else halt execution. - * @param message Message that should be printed before halting the execution if the condition is not met. - */ - auto assert(bool condition, char const * message) -> void; - -} // namespace teachos::arch::exception_handling - -#endif // TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP diff --git a/arch/x86_64/include/arch/exception_handling/panic.hpp b/arch/x86_64/include/arch/exception_handling/panic.hpp deleted file mode 100644 index 6a2404c..0000000 --- a/arch/x86_64/include/arch/exception_handling/panic.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP -#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP - -namespace teachos::arch::exception_handling -{ - /** - * @brief Print the given kernel panic message and then halt the system. - * - * @param reason Reason to print before halting the system. - */ - [[noreturn]] auto panic(char const * reason) -> void; - - /** - * @brief Print the given kernel panic message started by a given prefix and then halt the system. - * - * @param prefix Prefix to print before printing the reason. - * @param reason Reason to print before halting the system. - */ - [[noreturn]] auto panic(char const * prefix, char const * reason) -> void; - -} // namespace teachos::arch::exception_handling - -#endif // TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP diff --git a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp deleted file mode 100644 index 15b35c1..0000000 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP - -#include - -namespace teachos::arch::interrupt_handling -{ - /** - * @brief Represents the CPU state during an interrupt. - * - * Some interrupts push an error code, while others do not. The full list - * of which vector number contains the error code can be found here: https://wiki.osdev.org/Exceptions - */ - struct [[gnu::packed]] interrupt_frame - { - // uint64_t error_code; ///< Error code only pushed by some exceptions, therefore it is commented out. - uint64_t ip; ///< Instruction pointer at the time of the interrupt. - uint64_t cs; ///< Code segment selector indicating privilege level. - uint64_t flags; ///< CPU flags (RFLAGS) storing processor state. - uint64_t sp; ///< Stack pointer at the time of the interrupt. - uint64_t ss; ///< Stack segment selector, usually unused in 64-bit mode. - }; - - /** - * @brief Generic interrupt handler function. - * - * @param frame Pointer to the interrupt frame containing CPU state. - */ - [[gnu::interrupt]] - auto generic_interrupt_handler(interrupt_frame * frame) -> void; - -} // namespace teachos::arch::interrupt_handling - -#endif // TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/call.hpp b/arch/x86_64/include/arch/kernel/cpu/call.hpp deleted file mode 100644 index 3c43304..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/call.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Far Pointer. Address to function located in another code segment. - */ - struct far_pointer - { - void (*function)(); ///< Address of the function we want to call. (0-63) - context_switching::interrupt_descriptor_table::segment_selector - selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79) - }; - - /** - * @brief Far call - A call to an instruction located in a different segment than the current code segment but at the - * same privilege level. - * - * @param pointer 64-bit operand size far pointer that we want to call. - */ - auto call(far_pointer pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp deleted file mode 100644 index 68b950d..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP - -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - - /** - * @brief Returns the value in the GDTR register. - * - * @return Value of GDTR register. - */ - auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer; - - /** - * @brief Loads the global_descriptor_table_pointer into the global descriptor table register (GDTR). - */ - auto load_global_descriptor_table( - context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp deleted file mode 100644 index cb800d0..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Returns the value in the IDTR register. - * - * @return Value of IDTR register. - */ - auto store_interrupt_descriptor_table() - -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer; - - /** - * @brief Loads the interrupt_descriptor_table_pointer into the interrupt descriptor table register (IDTR). - */ - auto load_interrupt_descriptor_table( - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/if.hpp b/arch/x86_64/include/arch/kernel/cpu/if.hpp deleted file mode 100644 index 48707dc..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/if.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Sets the interrupt flag (IF) in the EFLAGS register. - * This allows the processor to respond to maskable hardware interrupts. - */ - auto set_interrupt_flag() -> void; - - /** - * @brief Clears the interrupt flag (IF) in the EFLAGS register. - * This will stop the processor to respond to maskable hardware interrupts and needs to be done before changing the - * Interrupt Descriptor Table with lidt. - */ - auto clear_interrupt_flag() -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/include/arch/kernel/cpu/msr.hpp deleted file mode 100644 index 99d6378..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/msr.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). - * - * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions - * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for - * more information. - */ - enum class efer_flags : uint64_t - { - SCE = 1UL << 0UL, ///< System Call Extensions. - LME = 1UL << 8UL, ///< Long Mode Enabled. - LMA = 1UL << 10UL, ///< Long Mode Active. - NXE = 1UL << 11UL, ///< No-Execute Enable. - SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. - LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. - FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. - TCE = 1UL << 15UL, ///< Translation Cache Extension. - }; - - /** - * @brief Reads a 64-bit from the Model-Specific Register (MSR). - * - * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper - * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. - * - * @param msr The address of the MSR to read. - * @return The 64-bit value read from the MSR. - */ - auto read_msr(uint32_t msr) -> uint64_t; - - /** - * @brief Writes a 64-bit value to a Model-Specific Register (MSR). - * - * @note This function writes a 64-bit value to the MSR specified by the given address. - * It splits the 64-bit value into two 32-bit parts and writes them using the - * `wrmsr` instruction. - * - * @param msr The address of the MSR to write to. - * @param new_value The 64-bit value to write to the MSR. - */ - auto write_msr(uint32_t msr, uint64_t new_value) -> void; - - /** - * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register - * (MSR). - * - * @note This function reads the current value of the EFER register, ORs the specified - * bit with the current value, and writes the updated value back to the EFER register. - * - * @param flag The flag to set in the EFER register. - */ - auto set_efer_bit(efer_flags flag) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp deleted file mode 100644 index a236452..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Clear all Data Segment registers (DS / ES / FS / GS). - */ - auto reload_data_segment_registers() -> void; - - /** - * @brief Updates the value of the Data Segment Register (DS), Extra Segment Register (ES), Thread-Local Storage - * Registers (FS / GS). - * - * @note The Stack Segment Register (SS) value should also be updated, but the value can not be directly set in - * comparsion to the other registers. This is the case because the register is used for stack management and can not - * be directly changed, instead this has to be done by a special instruction. Therefore - * validate_data_segment_registers should only be called after set_code_segment_register has been called as well. - * - * @param data_segment Value that should be loaded into the registers. - */ - auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void; - - /** - * @brief Returns the Segment Selector pointing to the Code Segment that has been loaded into the Code Segment - * Register (CS). - * - * @note The CS register can not be directly changed, instead a Far Return has to be executed to change it - * - * @return Segment Selector pointing to the currently loaded Code Segment. - */ - [[gnu::section(".user_text")]] - auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector; - - /** - * @brief Validates that all Data Segment Registers (DS / ES / FS / GS / SS) are the same as the given Data Segment - * and asserts and stops the application if they are not. - * - * @note This is only the case after set_code_segment_register has been executed as well, because it makes a far - * return that updates the SS register. - * - * @param data_segment Value that should be loaded into all Data Segment Registers. - */ - auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) - -> void; - - /** - * @brief Validates that the Code Segment Register (CS) is the same as the given Code Segment - * and asserts and stops the application if they are not. - * - * @param code_segment Value that should be loaded into the Code Segment Register. - */ - auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) - -> void; - - /** - * @brief Simply forwards the call to validate_data_segment_registers and validate_code_segment_register and ensures - * that all Segment Registers, have been configured correctly. - * - * @note If all Segment Register have been set correctly the Context Switch using the set_code_segment_register method - * was successfull and the Privilege Level has been changed. - * - * @param data_segment Value that should be loaded into all Data Segment Registers. - * @param code_segment Value that should be loaded into the Code Segment Register. - */ - auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void; - - /** - * @brief Sets the value of the Code Segment Register (CS), this is achieved using a Far Return. - * - * @note The Far Return used by this method, will cause the context to switch, because we are changing from the - * current Code Segment and it's associated Privilege Level to another Code Segment. The given method will then be - * called in the new context and it should be possible to call validate_segment_registers, with the same values - * without assertions if the switch was successful. - * - * To achieve this Far Return we call IRETQ, which expects the stack to be defined a certain way to achieve that we: - * 1. Push the Data Segment Selector - * 2. Push the current Stack Pointer - * 3. Push Eflags - * 4. Push Code Segment Selector - * 5. Push Return Address - * - * @param data_segment Data Segment that should be loaded into the SS register. - * @param code_segment Code Segment that should be loaded into the CS register. - * @param address Function that we want to call in the new context created by the given Code Segment. - */ - [[gnu::naked]] - auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, - uint64_t address) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/include/arch/kernel/cpu/tr.hpp deleted file mode 100644 index 7c856f1..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/tr.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - - /** - * @brief Returns the value in the LTR register. - * - * @return Value of LTR register. - */ - auto store_task_register() -> uint16_t; - - /** - * @brief Loads the gdt offset to the tss segment descriptor into the task register (TR). - */ - auto load_task_register(uint16_t gdt_offset) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP diff --git a/arch/x86_64/include/arch/kernel/halt.hpp b/arch/x86_64/include/arch/kernel/halt.hpp deleted file mode 100644 index 377acc0..0000000 --- a/arch/x86_64/include/arch/kernel/halt.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP - -namespace teachos::arch::kernel -{ - /** - * @brief Halts the kernel execution, meaning any code after a call to this will not run anymore. - */ - extern "C" [[noreturn]] auto halt() -> void; - -} // namespace teachos::arch::kernel - -#endif // TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp deleted file mode 100644 index a13e5f4..0000000 --- a/arch/x86_64/include/arch/kernel/main.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP - -namespace teachos::arch::kernel -{ - /** - * @brief Initalizes the kernel system. - */ - auto main() -> void; - -} // namespace teachos::arch::kernel - -#endif // TEACHOS_ARCH_X86_64_KERNEL_MAIN_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 a86c9b7..0000000 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP -#define TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP - -// #include "arch/memory/allocator/physical_frame.hpp" -// #include "arch/memory/multiboot/reader.hpp" - -#include - -namespace x86_64::memory -{ - /** - * @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; - - /** - * @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 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 x86_64::memory - -#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 - -namespace teachos::arch::memory::allocator -{ - /** - * @brief Frame allocator concept required for allocating and deallocating physical frames in memory. - */ - template - concept FrameAllocator = requires(T t, physical_frame const & a) { - { t.allocate_frame() } -> std::same_as>; - { t.deallocate_frame(a) } -> std::same_as; - }; - -} // namespace teachos::arch::memory::allocator - -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_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 - -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 - 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; - - /** - * @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, 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/heap/bump_allocator.hpp b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp deleted file mode 100644 index 011f45c..0000000 --- a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP - -#include "arch/memory/heap/heap_allocator.hpp" - -#include -#include - -namespace teachos::arch::memory::heap -{ - /** - * @brief Simple heap allocator, which allocates linearly and leaks all allocated memory, because it does not really - * deallocate anything. - */ - struct bump_allocator : heap_allocator - { - /** - * @brief Constructor. - * - * @param heap_start Start of the allocatable heap area - * @param heap_end End of the allocatable heap area (Start + Size) - */ - bump_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start{heap_start} - , heap_end{heap_end} - , next{heap_start} - { - // Nothing to do - } - - auto allocate(std::size_t size) -> void * override; - - /** - * @copybrief heap_allocator::deallocate - * - * @note Simply does nothing, because this allocator leaks all memory - */ - auto deallocate(void * pointer) noexcept -> void override; - - private: - std::size_t heap_start; ///< Start of the allocatable heap area - std::size_t heap_end; ///< End of the allocatable heap area - std::atomic_uint64_t next; ///< Current address, which is the start of still unused allocatable heap area - }; - -} // namespace teachos::arch::memory::heap - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp deleted file mode 100644 index c98c130..0000000 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_GLOBAL_HEAP_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_GLOBAL_HEAP_ALLOCATOR_HPP - -#include "arch/memory/heap/heap_allocator.hpp" -#include "arch/memory/heap/user_heap_allocator.hpp" - -namespace teachos::arch::memory::heap -{ - /** - * @brief Possible types that should be constructed by the register_heap_allocator factory method. - * Creates the underlying heap allocator instance that is then used by all global allocations using new and delete - */ - enum class heap_allocator_type : uint8_t - { - NONE, ///< Don't use any heap allocation implementation, this will result in all calls of new and delte halting - ///< further execution of the kernel - BUMP, ///< Use the bump allocator as the heap allocation implementation, be aware that using this allocator leaks - ///< memory, because there is no delete implementation - LINKED_LIST ///< Use the linked list allocator as the heap implementation, recommended because it does not leak - ///< memory - }; - - /** - * @brief Global instance of a heap allocator implementation created by the factory method pattern @see - * https://refactoring.guru/design-patterns/factory-method for more information. - * - * @note Can only be registered once and only once the kernel and the heap part of the kernel has been remapped - * successfully. If the instance is created before than the device will abort, because it acceses unmapped memory - * areas. - */ - struct global_heap_allocator - { - /** - * @brief Registers the heap allocation implementation that should be used by the global heap allocator. - * Meaning all future calls to the global new or delete will be forwarded to the allocate and deallocate calls of - * the underlying heap allocation implementation - * - * @param new_type Type of the heap allocation implementation we want to instantiate - */ - static auto 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. - * Simply forwards the call to the allocate method of the registered heap_allocation implementation - * - * @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 *; - - /** - * @brief Deallocated all memory associated with the memory area starting from the given pointer address. - * Simply forwards the call to the deallocate method of the registered heap_allocation implementation - * - * @param pointer Previously allocated memory area, that should now be freed - */ - static auto kfree(void * pointer) noexcept -> void; - - /** - * @brief Allocates the given amount of memory and returns the pointer to the start of the allocatable memory area. - * Simply forwards the call to the allocate method of the registered heap_allocation implementation - * - * @param size Amount of bytes that should be allocated - * @return void* Pointer to the start of the allocatable memory area - */ - [[gnu::section(".user_text")]] - static auto malloc(std::size_t size) -> void *; - - /** - * @brief Deallocated all memory associated with the memory area starting from the given pointer address. - * Simply forwards the call to the deallocate method of the registered heap_allocation implementation - * - * @param pointer Previously allocated memory area, that should now be freed - */ - [[gnu::section(".user_text")]] - static auto 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 * - user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory - - /** - * @brief Either returns the previously registered heap allocated or halts further execution - * - * @return Reference to the registered kernel heap allocation - */ - static auto 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 &; - }; -} // namespace teachos::arch::memory::heap - -[[gnu::section(".user_text")]] -auto operator new(std::size_t size) -> void *; - -[[gnu::section(".user_text")]] -auto operator delete(void * pointer) noexcept -> void; - -[[gnu::section(".user_text")]] -auto operator delete(void * pointer, std::size_t size) noexcept -> void; - -[[gnu::section(".user_text")]] -auto operator new[](std::size_t size) -> void *; - -[[gnu::section(".user_text")]] -auto operator delete[](void * pointer) noexcept -> void; - -[[gnu::section(".user_text")]] -auto operator delete[](void * pointer, std::size_t size) noexcept -> void; - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_GLOBAL_HEAP_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp b/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp deleted file mode 100644 index 420a1d3..0000000 --- a/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_HEAP_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_HEAP_ALLOCATOR_HPP - -#include - -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; - - /** - * @brief Heap allocator interface containing methods required to allocate and deallocate heap memory areas - */ - struct heap_allocator - { - /** - * @brief Virtual default destructor, created to ensure that if a pointer to this class is used and deleted, we will - * also call the derived base class destructor. Deleting a base class destructor that does not have a virtual - * destructor is undefined behaviour, because the derived class destructor originally instantiated with new is never - * called. This can cause potential memory leaks, because derived classes can not clean up their internal members as - * expected and instead simply leak them - */ - virtual ~heap_allocator() {} - - /** - * @brief Allocates the given amount of memory and returns the pointer to the start of the allocatable memory area - * - * @param size Amount of bytes that should be allocated - * @return void* Pointer to the start of the allocatable memory area - */ - virtual auto allocate(std::size_t size) -> void * = 0; - - /** - * @brief Deallocates all memory associated with the given pointer address. - * Simply deallocates the amount of memory created with the corresponding call to allocate - * - * @param pointer Previously allocated memory area, that should now be freed - */ - virtual auto deallocate(void * pointer) noexcept -> void = 0; - }; -} // namespace teachos::arch::memory::heap - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_HEAP_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp deleted file mode 100644 index bbbad19..0000000 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP - -#include "arch/memory/heap/heap_allocator.hpp" -#include "arch/memory/heap/memory_block.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - /** - * @brief Sorted by address list of memory holes (free memory). Uses free holes itself to save the information, - * containing the size and pointer to the next hole. Resulting in a singly linked list. - */ - struct linked_list_allocator : heap_allocator - { - /** - * @brief Constructor. - * - * @param heap_start Start of the allocatable heap area - * @param heap_end End of the allocatable heap area (Start + Size) - */ - linked_list_allocator(std::size_t heap_start, std::size_t heap_end); - - /** - * @copybrief heap_allocator::allocate - * - * @note The specified size is used to find a free memory block with the exact same size, meaning we can remove that - * free memory block from the free list and simply return its address. Or it has to be big enough to hold the size - * and alteast enough memory for another free memory block entry (16 bytes). If the amount of memory of that free - * memory block is in between we cannot use it for our allocation, because we could only return it to the user, but - * the additional bytes, could not be used to create a free memory block. Additionaly the user couldn't know - * they received more memory than wanted. Therefore the memory would simply be unused and because it is neither - * allocated nor deallocated would never be indexed by the free memory list. We would therefore permanently loose - * that memory, to prevent that allocation into free memory blocks like that are impossible. - */ - auto allocate(std::size_t size) -> void * override; - - auto deallocate(void * pointer) noexcept -> void override; - - private: - /** - * @brief Returns the smallest allocatable block of heap memory. - * - * @return Smallest allocatable block of heap memory. - */ - auto constexpr 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. - * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to - * allocate the required size into. - * @param current_block Free memory block we want to remove from the free list and return for the allocation. - * - * @return Previous start address of the memory block we removed, because it can now be used for the allocation. - */ - auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void *; - - /** - * @brief Splits the given free memory block into two, where the latter block keeps being free and the first - * part will be used for the allocation. - * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to - * allocate the required size into. - * @param current_block Free memory block we want to split into a size part for the allocation and the rest for - * future allocations. - * @param size Size we want to allocate at the start of the free memory block. - * - * @return Previous start address of the memory block we just split, because it can now be used for the allocation. - */ - auto split_free_memory_block(memory_block * previous_block, memory_block * current_block, std::size_t size) - -> void *; - - /** - * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. - * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to - * allocate the required size into. - * @param current_block Free memory block we want to remove from the free list and return for the allocation. - * @param new_block Replaces the current block with the given new block can be nullptr, meaning the free list will - * end here. - * - * @return Previous start address of the memory block we removed, because it can now be used for the allocation. - */ - auto replace_free_memory_block(memory_block * previous_block, memory_block * current_block, - memory_block * new_block) -> void *; - - /** - * @brief Combines multiple free memory blocks into one if they are adjacent. - * - * @note The internal algorithm for recombination functions like this: - * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and - * we can therefore set the first entry to our newly created entry. This entry is created in the now deallocated - * memory area. - * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a - * new free memory block of the given size and set the previous next to our block and the next of our block to - * the current block. - * 3. If the current block is adjacent the start address of the newly created block stays the same, but the size - * increases by the amount in the current memory block header. After reading it we also clear the header. - * 4. If the previous block is adjacent the size of the previous block simply increases to include the given - * size as well. - * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of - * the region we are trying to deallocate has been freed before. Which would result in a double free therefore - * we halt the execution of the program. - * - * @param previous_block Free memory block before the block to deallocate in our heap memory. - * @param current_block Free memory block after the block to deallocate in our heap memory. - * @param pointer Block to deallocate. - * @param size Size of the block we want to deallocate. - */ - auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, - std::size_t size) -> void; - - memory_block * first; ///< First free entry in our memory. - kstd::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. - }; -} // namespace teachos::arch::memory::heap - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp deleted file mode 100644 index 9d1fb02..0000000 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP - -#include - -namespace teachos::arch::memory::heap -{ - /** - * @brief Block containing free memory, pointing to the next free hole (nullptr) if there is none. - * Forms a singly linked list of free memory blocks that we can callocate memory into. - */ - struct memory_block - { - /** - * @brief Constructor. Clears all memory from the place it was allocated until the end (address + - * size). - * - * @param size Amount of free memory of this specific hole. - * @param next Optional pointer to the next free memory. - */ - [[gnu::section(".user_text")]] - memory_block(std::size_t size, memory_block * next); - - /** - * @brief Destructor. Clears all internal memory. - * - * @note Used so the memory can be reused to construct other classes into, without having the old values. - * Required because we cannot call delete, because it causes "undefined reference to `sbrk`". - */ - [[gnu::section(".user_text")]] - ~memory_block(); - - std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the - ///< size variable and the pointer to the next hole. - memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. - }; -} // namespace teachos::arch::memory::heap - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP diff --git a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp b/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp deleted file mode 100644 index 3b47f15..0000000 --- a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_ALLOCATOR_HPP - -#include "arch/memory/heap/memory_block.hpp" - -// #include -#include -#include - -namespace teachos::arch::memory::heap -{ - /** - * @brief Sorted by address list of memory holes (free memory). Uses free holes itself to save the information, - * containing the size and pointer to the next hole. Resulting in a singly linked list. - */ - struct user_heap_allocator - { - /** - * @brief Constructor. - */ - user_heap_allocator() = default; - - /** - * @copybrief heap_allocator::allocate - * - * @note The specified size is used to find a free memory block with the exact same size, meaning we can remove that - * free memory block from the free list and simply return its address. Or it has to be big enough to hold the size - * and alteast enough memory for another free memory block entry (16 bytes). If the amount of memory of that free - * memory block is in between we cannot use it for our allocation, because we could only return it to the user, but - * the additional bytes, could not be used to create a free memory block. Additionaly the user couldn't know - * they received more memory than wanted. Therefore the memory would simply be unused and because it is neither - * allocated nor deallocated would never be indexed by the free memory list. We would therefore permanently loose - * that memory, to prevent that allocation into free memory blocks like that are impossible. - */ - [[gnu::section(".user_text")]] - auto allocate(std::size_t size) -> void *; - - /** - * @copybrief heap_allocator::deallocate - */ - [[gnu::section(".user_text")]] - auto deallocate(void * pointer) noexcept -> void; - - private: - /** - * @brief Returns the smallest allocatable block of heap memory. - * - * @return Smallest allocatable block of heap memory. - */ - [[gnu::section(".user_text")]] auto constexpr 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. - * - * @note Adjusts the link of the previous memory block to the new smaller remaining block. If the allocation used - * the complete block instead the previous block will point to the next block of the current memroy block that was - * used for the allocation. - * - * @return Allocated usable memory area. - */ - [[gnu::section(".user_text")]] auto - allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, std::size_t total_size) - -> std::optional; - - /** - * @brief Special functionality fo the user heap allocator. Which will result in it being expanded by a syscall with - * addtionally 100 KiB, which are mapped into the page table. Will always work until there is no physical memory - * left. - * - * @return Start of the newly with syscall allocated free memory block. Nullptr if the syscall failed. - */ - [[gnu::section(".user_text")]] auto expand_heap_if_full() -> memory_block *; - - /** - * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. - * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to - * allocate the required size into. - * @param current_block Free memory block we want to remove from the free list and return for the allocation. - * - * @return Previous start address of the memory block we removed, because it can now be used for the allocation. - */ - [[gnu::section(".user_text")]] - auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void *; - - /** - * @brief Splits the given free memory block into two, where the latter block keeps being free and the first - * part will be used for the allocation. - * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to - * allocate the required size into. - * @param current_block Free memory block we want to split into a size part for the allocation and the rest for - * future allocations. - * @param size Size we want to allocate at the start of the free memory block. - * - * @return Previous start address of the memory block we just split, because it can now be used for the allocation. - */ - [[gnu::section(".user_text")]] - auto split_free_memory_block(memory_block * previous_block, memory_block * current_block, std::size_t size) - -> void *; - - /** - * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. - * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to - * allocate the required size into. - * @param current_block Free memory block we want to remove from the free list and return for the allocation. - * @param new_block Replaces the current block with the given new block can be nullptr, meaning the free list will - * end here. - * - * @return Previous start address of the memory block we removed, because it can now be used for the allocation. - */ - [[gnu::section(".user_text")]] - auto replace_free_memory_block(memory_block * previous_block, memory_block * current_block, - memory_block * new_block) -> void *; - - /** - * @brief Combines multiple free memory blocks into one if they are adjacent. - * - * @note The internal algorithm for recombination functions like this: - * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and - * we can therefore set the first entry to our newly created entry. This entry is created in the now deallocated - * memory area. - * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a - * new free memory block of the given size and set the previous next to our block and the next of our block to - * the current block. - * 3. If the current block is adjacent the start address of the newly created block stays the same, but the size - * increases by the amount in the current memory block header. After reading it we also clear the header. - * 4. If the previous block is adjacent the size of the previous block simply increases to include the given - * size as well. - * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of - * the region we are trying to deallocate has been freed before. Which would result in a double free therefore - * we halt the execution of the program. - * - * @param previous_block Free memory block before the block to deallocate in our heap memory. - * @param current_block Free memory block after the block to deallocate in our heap memory. - * @param pointer Block to deallocate. - * @param size Size of the block we want to deallocate. - */ - [[gnu::section(".user_text")]] - auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, - std::size_t size) -> void; - - memory_block * first = {}; ///< First free entry in our memory. - kstd::mutex mutex = {}; ///< Mutex to ensure only one thread calls allocate or deallocate at once. - }; -} // namespace teachos::arch::memory::heap - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_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 - -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 348c159..0000000 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ /dev/null @@ -1,170 +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 -#include - -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>; - -} // 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/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp deleted file mode 100644 index c5464cb..0000000 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ /dev/null @@ -1,58 +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 "arch/memory/multiboot/elf_symbols_section.hpp" - -#include -#include -#include - -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. - multiboot2::elf_symbols; ///< 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. - // std::sp - // 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 -#include -#include - -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; - - /** - * @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; - - /** - * @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; - - /** - * @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 - 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 - 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 - 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 - 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 - 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 3afb54b..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 -#include - -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 - 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 constexpr USER_SECTION_BASES = { - 0x102000, // .boot_bss (Contains statically allocated variables) - 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) - 0x217000, // .user_text (Contains the actual user code executed) - 0x21E000, // .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 -#include - -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; - - /** - * @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; - - /** - * @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 - 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 - 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 -#include -#include - -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>; - -} // namespace teachos::arch::memory::paging - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/include/arch/user/main.hpp b/arch/x86_64/include/arch/user/main.hpp deleted file mode 100644 index c168a1f..0000000 --- a/arch/x86_64/include/arch/user/main.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_USER_MAIN_HPP -#define TEACHOS_ARCH_X86_64_USER_MAIN_HPP - -namespace teachos::arch::user -{ - /** - * @brief User Main method. If this method finishes there is no code left to run and the whole OS will shut down. - * Additionally this main method is executed at Ring 3 and accessing CPU Registers or Kernel level functionality can - * only be done over syscalls and not directly anymore. - */ - [[gnu::section(".user_text")]] - auto main() -> void; - -} // namespace teachos::arch::user - -#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..07110c8 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp @@ -0,0 +1,69 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP + +#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" +#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +#include +#include + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + __extension__ typedef __int128 int128_t; + __extension__ typedef unsigned __int128 uint128_t; + + /** + * @brief Defines helper function for all states and the actual data the gate descriptor can have. + */ + struct [[gnu::packed]] gate_descriptor + { + /** + * @brief Default Constructor. + */ + gate_descriptor() = default; + + /** + * @brief Constructor. + * + * @note Created gate descriptor copies the given bytes into these components ending with a 32 bit reserved + * field that has to be used, because the 64-bit gate descriptor needs to be big enough for two 32-bit gate + * descriptor. + * - 16 bit Segment Selector + * - 3 bit Interrupt Stack Table Offset + * - 8 bit Type and Flags + * - 64 bit Offset + * + * @param flags Copies the bits set from the given data into the individual components of a gate + * descriptor. + */ + explicit gate_descriptor(uint128_t flags); + + /** + * @brief Constructor. + * + * @param selector, ist, flags, offset Copies the bits set from the given data into the individual components of + * a gate descriptor. + */ + gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset); + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(gate_descriptor const & other) const -> bool = default; + + private: + // The order in private variables starts for the first variable being the rightmost bit. + uint16_t _offset_1 = {}; ///< Lower 16 bits of handler function address (0 - 15) + segment_selector _selector = {}; ///< Segment selector (16 - 31) + ist_offset _ist = {}; ///< Interrupt Stack Table offset (32 - 39) + idt_flags _flags = {}; ///< Gate Type and Flags (40 - 47) + uint64_t _offset_2 : 48 = {}; ///< Upper 48 bits of handler function address (48 - 95) + uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..5104c36 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp @@ -0,0 +1,81 @@ + +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP + +#include +#include + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Defines helper function for all states that the access byte field of a segment descriptor can + * have. + */ + struct [[gnu::packed]] idt_flags + { + /** + * @brief Possible set bits in our underlying bits and the meaning when they are set. + */ + enum bitset : uint8_t + { + INTERRUPT_GATE = 0b01110, ///< The actual type of gate segment is a interrupt gate. + TRAP_GATE = 0b01111, ///< The actual type of gate segment is a trap gate. + DESCRIPTOR_LEVEL_KERNEL = + 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. + DESCRIPTOR_LEVEL_ADMIN = + 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + DESCRIPTOR_LEVEL_PRIVILEGED_USER = + 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. + PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. + }; + + /** + * @brief Default Constructor. + */ + idt_flags() = default; + + /** + * @brief Constructor. + * + * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used + * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags + * are enabled or not using contains_flags method. + */ + idt_flags(uint8_t flags); + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * data. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying data has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying data. + */ + auto contains_flags(std::bitset<8U> other) const -> bool; + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(idt_flags const & other) const -> bool = default; + + /** + * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. + * + * @param other Additional bits that should be set. + */ + auto operator|=(std::bitset<8U> other) -> void; + + private: + uint8_t _flags = {}; ///< Underlying bits used to read the flags from. + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP \ No newline at end of file diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..b388e0e --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp @@ -0,0 +1,24 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Updates the IDTR with the created interrupt descriptor table. If it has not been created yet this + * method will create it. + */ + auto update_interrupt_descriptor_table_register() -> void; + + /** + * @brief Creates the interrupt descriptor table, with the minimum required configuration. If this method is called + * more than once, the previously created instance is returned instead. + * + * @return Reference to the created interrupt_descriptor_table. + */ + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &; + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..7fe933b --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp @@ -0,0 +1,40 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" +#include "arch/stl/vector.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + using interrupt_descriptor_table = stl::vector; + + /** + * @brief Represents a pointer to the Interrupt Descriptor Table (IDT). + * + * This structure is used to store the base address and length of the IDT. + */ + struct [[gnu::packed]] interrupt_descriptor_table_pointer + { + /** + * @brief Default constructor. + */ + interrupt_descriptor_table_pointer() = default; + + /** + * @brief Constructor. + */ + interrupt_descriptor_table_pointer(uint16_t table_length, gate_descriptor * address); + + /** + * @brief Defaulted three-way comparsion operator. + */ + auto operator<=>(interrupt_descriptor_table_pointer const & other) const -> std::strong_ordering = default; + + private: + uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. + gate_descriptor * address = {}; ///< Non-owning pointer to the IDT base address. + }; + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..e45bcf4 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp @@ -0,0 +1,45 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP + +#include +#include + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Defines helper function for all states that the interrupt stack table offset field of a gate descriptor can + * have. Is automatically increased to one byte in size, to include the following 5 reserved bits in the gate + * descriptor. + */ + struct [[gnu::packed]] ist_offset + { + /** + * @brief Default Constructor. + */ + ist_offset() = default; + + /** + * @brief Constructor. + * + * @param offset Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, whereas 1 - 7 + * mean we switch to the n-th stack in the Interrupt Stack Table, contained in the TSS if the gate descriptor that + * contains this field is called. + */ + ist_offset(uint8_t offset); + + /** + * @brief Allows to compare the underlying set bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(ist_offset const & other) const -> bool = default; + + private: + uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, + ///< whereas 1 - 7 mean we switch to the n-th stack in the Interrupt Stack Table, contained + ///< in the TSS if the gate descriptor that contains this field is called. + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..2a7704e --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp @@ -0,0 +1,105 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP + +#include +#include + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Represents a segment selector in the x86_64 architecture, which points to a valid code segment in the global + * descriptor table. + * + * A segment selector is a 16-bit identifier used to select a segment descriptor + * from the Global Descriptor Table (GDT) or the Local Descriptor Table (LDT). + * It contains an index, a table indicator (TI), and a requested privilege level (RPL). + */ + struct [[gnu::packed]] segment_selector + { + /** + * @brief Possible set bits in our underlying bits and the meaning when they are set. + */ + enum bitset : uint8_t + { + REQUEST_LEVEL_KERNEL = + 0U << 0U, ///< Highest privileged level used by the kernel to allow for full access of resources. + REQUEST_LEVEL_ADMIN = + 1U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + REQUEST_LEVEL_PRIVILEGED_USER = + 2U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + REQUEST_LEVEL_USER = 3U << 0U, ///< Restricts access to only application and their specific memory. + LOCAL_DESCRIPTOR_TABLE = 1U << 2U, ///< Wheter the index referes to an entry in the local or global descriptor + ///< table. If enabled the index points to a local descriptor table, if it is + ///< cleared it referes to a global descriptor table instead. + }; + + /** + * @brief Default constructor. + */ + segment_selector() = default; + + /** + * @brief Constructor. + * + * @param index Index into the local or global descriptor table. Processor multiplies the index value by 8 (number + * of bytes in 32-bit segment descriptor) and adds the result to the base GDT or LDT address. + * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to + * allow for direct integer conversion. + */ + constexpr segment_selector(uint16_t index, uint8_t flags) + : _flags(flags) + , _index(index) + { + // Nothing to do. + } + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * data. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying data has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying data. + */ + auto contains_flags(std::bitset<3U> other) const -> bool; + + /** + * @brief Gets the index into the global descriptor table or the local descriptor table this segment selector is + * pointing too. + * + * @return Underlying value of the index field, bit 3 - 16. + */ + [[gnu::section(".user_text")]] + auto get_index() const -> uint16_t; + + /** + * @brief Defaulted three-way comparsion operator. + */ + auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; + + /** + * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. + * + * @param other Additional bits that should be set. + */ + auto operator|=(std::bitset<3U> other) -> void; + + /** + * @brief Cast the underlying data into a combined 16-bit form, that contains all data. + * + * @return Underlying value combined into it's full size. + */ + operator uint16_t() const; + + 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. + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/main.hpp b/arch/x86_64/pre/include/arch/context_switching/main.hpp new file mode 100644 index 0000000..f8477ea --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/main.hpp @@ -0,0 +1,51 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP + +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" + +namespace teachos::arch::context_switching +{ + /** + * @brief Contains the references to the tables required for context switching + */ + struct descriptor_tables + { + segment_descriptor_table::global_descriptor_table & gdt; ///< Reference to the global descriptor table. + interrupt_descriptor_table::interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. + }; + + /** + * @brief Creates the Interrupt Descriptor Table and Global Descriptor Table as a static variable the first time this + * method is called and update IDTR and GDTR registers values. + * + * @note Subsequent calls after the first one, will simply return the previously created tables, but not update the + * registers again. + * + * @return References to the statically created Interrupt Descriptor and Global Descriptor Table. + */ + auto initialize_descriptor_tables() -> descriptor_tables; + + /** + * @brief Switches from the current Kernel Mode (Level 0) to User Mode (Level 3). Will simply use predefined Segment + * Selectors for the User Data and User Code Segment, which are Index 3 and 4 in the GDT respectively. + */ + auto switch_to_user_mode() -> void; + + /** + * @brief Switches from the current Code and Data Segment to the given Code and Data Segment. + * + * @note This method will additionally call initialize_descriptor_tables, to ensure the GDTR and IDTR have been setup + * correctly before attempting to switch the context. This switch is achieved using a far return, which will once + * executed call the given void function. + * + * @param data_segment Data Segment that the SS, DS; ES, FS and GS register will be set too. + * @param code_segment Code Segment that the CS register will be set too. + * @param return_function Function that will be called once the switch has been achieved. + */ + auto switch_context(interrupt_descriptor_table::segment_selector data_segment, + interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void; + +} // namespace teachos::arch::context_switching + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..7450330 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/access_byte.hpp @@ -0,0 +1,104 @@ + +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP + +#include +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief Defines helper function for all states that the access byte field of a segment descriptor can + * have. + */ + struct [[gnu::packed]] access_byte + { + /** + * @brief Possible set bits in our underlying bits and the meaning when they are set. + */ + enum bitset : uint8_t + { + ACCESSED = + 1U + << 0U, ///< Whether the segment has been accessed since the last time the operating system has cleared the + ///< flag. If enabled it has been accessed, otherwise it has not been accessed since the last clear. + WRITABLE = 1U << 1U, ///< Indicates if the data segment is writable or not. If enabled the code segment allows + ///< read and write access, otherwise only read access is possible. + READABLE = 1U << 1U, ///< Indicates if the code segment is readable or not. If enabled the code segment allows + ///< read and execute access, otherwise only executable access is possible. + CONFORMING = + 1U << 2U, ///< Indicates if the code is allowed to be executed by different access levels + ///< (higher or lower) in code segments. If enabled the code segment allows access, otherwise + ///< access from different privilege levels with throw a General-Protectione exception. + EXPAND_DOWN = 1U << 2U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the + ///< data segment expands downwards, otherwise it expands upwards. + CODE_SEGMENT = 1U << 3U, ///< Further defines the actual type of the segment. If enabled this segment is a code + ///< segment, otherwise its a data segment. + LOCAL_DESCRIPTOR_TABLE = 2, ///< The actual type of sytem segment is a local descriptor table. + TASK_STATE_SEGMENT_AVAILABLE = + 9, ///< The actual type of sytem segment is a task state segment that is still available. + TASK_STATE_SEGMENT_BUSY = 11, ///< The actual type of sytem segment is a task state segment that is currently in + ///< use and therefore busy. + CALL_GATE = 11, ///< The actual type of sytem segment is a call gate. + INTERRUPT_GATE = 14, ///< The actual type of sytem segment is a interrupt gate. + TRAP_GATE = 15, ///< The actual type of sytem segment is a trap gate. + CODE_OR_DATA_SEGMENT = 1U << 4U, ///< Defines a system segment (if 0) or a code/data segment (if 1). + DESCRIPTOR_LEVEL_KERNEL = + 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. + DESCRIPTOR_LEVEL_ADMIN = + 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + DESCRIPTOR_LEVEL_PRIVILEGED_USER = + 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. + PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. + }; + + /** + * @brief Default Constructor. + */ + access_byte() = default; + + /** + * @brief Constructor. + * + * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used + * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags + * are enabled or not using contains_flags method. + */ + access_byte(uint8_t flags); + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * data. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying data has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying data. + */ + auto contains_flags(std::bitset<8U> other) const -> bool; + + /** + * @brief Allows to compare the underlying data of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying data of both types is the same. + */ + auto operator==(access_byte const & other) const -> bool = default; + + /** + * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. + * + * @param other Additional bits that should be set. + */ + auto operator|=(std::bitset<8U> other) -> void; + + private: + uint8_t _flags = {}; ///< Underlying bits used to read the flags from. + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP \ No newline at end of file diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..e24b988 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp @@ -0,0 +1,93 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GDT_FLAGS_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GDT_FLAGS_HPP + +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief Defines helper function for all states that the flags field of a segment descriptor can + * have. + */ + struct [[gnu::packed]] gdt_flags + { + /** + * @brief Possible set bits in our underlying bits and the meaning when they are set. + */ + enum bitset : uint8_t + { + LONG_MODE = 1U << 1U, ///< Defines in IA-32e mode (64-bit code and 32-bit compatability mode) if the segment + ///< contains 64-bit code. Otherwise this bit should always be 0. Enable if instructions + ///< are executed in 64-bit code, otherwise they are executed in compatability 32-bit mode. + ///< If this bit is set the 3rd bit needs to be clear (0). + UPPER_BOUND = 1U << 2U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 4 + ///< GiB, 4 KiB otherwise. + STACK_POINTER_SIZE = 1U << 2U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for + ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. + DEFAULT_LENGTH = 1U << 2U, ///< Indicates the default length for code segments with effective addresses and + ///< operands. Enable for 32 bit, 16 bit otherwise. + GRANULARITY = 1U << 3U, ///< Indicates the size the Limit value in the segment descriptor is scaled by 1 Byte + ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. + }; + + /** + * @brief Default Constructor. + */ + gdt_flags() = default; + + /** + * @brief Constructor. + * + * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to + * allow for direct integer conversion. This value is saved and can later be used to check whether certain flags are + * enabled or not using contains_flags method. + * @param limit Does not necessarily make sense in the gdt flags type, but because the flags alone are only 4 bit + * the type would still require the space for a complete bit. Therefore the 4 bit segment limit field before the + * flags field is included in this type to ensure we actually contain 8 bit of data. + */ + gdt_flags(uint8_t flags, std::bitset<20U> limit); + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * data. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying data has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying data. + */ + auto contains_flags(std::bitset<4U> other) const -> bool; + + /** + * @brief Get part of the segment limit that is saved in the gdt flags. This does not necessarily make sense in this + * object, but it has to be included here because a struct can not be smaller than a full byte. Therefore we include + * the 4 bit segment limit field so that it results in a compelte byte with the addtional 4 bit of gdt flags. + * + * @return 4-bit limit segment + */ + auto get_limit() const -> std::bitset<4U>; + + /** + * @brief Allows to compare the underlying set bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(gdt_flags const & other) const -> bool = default; + + /** + * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. + * + * @param other Additional bits that should be set. + */ + auto operator|=(std::bitset<4U> other) -> void; + + private: + uint8_t _limit_2 : 4 = {}; ///< Second part of the limit field. + uint8_t _flags : 4 = {}; ///< Underlying bits used to read the flags from. + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GDT_FLAGS_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..44f2692 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/segment_descriptor_table/task_state_segment.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief Creates the global descriptor table, with the minimum required configuration. If this method is called more + * than once, the previously created instance is returned instead. + * + * @return Reference to the created global_descriptor_table. + */ + auto get_or_create_gdt() -> global_descriptor_table &; + + /** + * @brief Updates the GDTR with the created global descriptor table. If it has not been created yet this + * method will create it. + * + * @note This method will only set the GDTR, but for the processor to actually register the change a far jump + * has to be executed. This also has to be done before updating the TR. + */ + auto update_gdtr() -> void; + + /** + * @brief Updates the TR with the created task state segment. If it has not been created yet this + * method will create it. + * + * @note This method should only be called after update_gdtr() and a far jump has been + * executed. Because before that trying to access the segment will cause an exception. + */ + auto update_tss_register() -> void; + +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..292ff70 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp @@ -0,0 +1,41 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/stl/vector.hpp" + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + using global_descriptor_table = stl::vector; + + /** + * @brief Represents a pointer to the Global Descriptor Table (GDT). + * + * This structure is used to store the base address and length of the GDT. + * It is used when loading or modifying the GDT during context switching. + */ + struct [[gnu::packed]] global_descriptor_table_pointer + { + /** + * @brief Default constructor. + */ + global_descriptor_table_pointer() = default; + + /** + * @brief Constructor. + */ + global_descriptor_table_pointer(uint16_t table_length, uint64_t * address); + + /** + * @brief Defaulted three-way comparsion operator. + */ + auto operator<=>(global_descriptor_table_pointer const & other) const -> std::strong_ordering = default; + + private: + uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. + uint64_t * address = {}; ///< Non-owning pointer to the GDT base address. + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..933fb4d --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp @@ -0,0 +1,73 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_BASE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_BASE_HPP + +#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" +#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief Defines helper function for all states and the actual data the segment descriptor can have. + */ + struct [[gnu::packed]] segment_descriptor_base + { + /** + * @brief Default Constructor. + */ + segment_descriptor_base() = default; + + /** + * @brief Constructor. + * + * @note Created segment descriptor copies the given bytes into these components requiring the space of one + * segment descriptor entry in the global descriptor table being 64-bit. + * - 8 bit Access Type + * - 4 bit Flags + * - 32 bit Base Address + * - 20 bit Limit + * + * @param flags Copies the bits set from the given data into the individual components of a segment + * descriptor. + */ + explicit segment_descriptor_base(uint64_t flags); + + /** + * @brief Constructor. + * + * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of + * a segment descriptor. + */ + segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, std::bitset<20U> limit); + + /** + * @brief Calculates the underlying segment type that this segement descriptor is describing. + */ + auto get_segment_type() const -> segment_descriptor_type; + + /** + * @brief Cast the underlying data into a combined 64-bit form, that contains all data. + * + * @return Underlying value combined into it's full size. + */ + operator uint64_t() const; + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(segment_descriptor_base const & other) const -> bool = default; + + private: + // The order in private variables starts for the first variable being the rightmost bit. + uint16_t _limit_1 = {}; ///< First part of the limit field (0 - 15) + uint32_t _base_1 : 24 = {}; ///< First part of the base field (16 - 39) + access_byte _access = {}; ///< Access byte field (40 - 47) + gdt_flags _flag = {}; ///< Second part of the limit field + Flags field (48 - 55) + uint8_t _base_2 = {}; ///< Second part of the base field (56 - 63) + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_BASE_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..40bcc8a --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp @@ -0,0 +1,74 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP + +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + __extension__ typedef __int128 int128_t; + __extension__ typedef unsigned __int128 uint128_t; + + /** + * @brief Defines helper function for all states and the actual data the segment descriptor can have. + */ + struct [[gnu::packed]] segment_descriptor_extension + { + /** + * @brief Default Constructor. + */ + segment_descriptor_extension() = default; + + /** + * @brief Constructor. + * + * @note Created segment descriptor copies the given bytes into these components requiring the space of two + * segment descriptor entry in the global descriptor table being 128-bit. Ending with a 32 bit reserved + * field that has to be used, because the segment descriptor needs to be big enough for two segment + * descriptor entries. + * - 8 bit Access Type + * - 4 bit Flags + * - 64 bit Base Address + * - 20 bit Limit + * + * @param flags Copies the bits set from the given data into the individual components of a segment + * descriptor. + */ + explicit segment_descriptor_extension(uint128_t flags); + + /** + * @brief Constructor. + * + * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of + * a segment descriptor. + */ + segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit); + + /** + * @brief Returns the underlying base segment descriptor, being the first part of the segment descriptor consisting + * of two entries in the global descriptor table. + */ + auto get_first_gdt_entry() const -> segment_descriptor_base; + + /** + * @brief Returns the underlying extension to the segment descriptor, being the second part of the segment + * descriptor consiting of two entries in the global descriptor table. + */ + auto get_second_gdt_entry() const -> uint64_t; + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(segment_descriptor_extension const & other) const -> bool = default; + + private: + // The order in private variables starts for the first variable being the rightmost bit. + segment_descriptor_base _base = {}; ///< Base Segment Descriptor representing single entry in GDT (0 - 63) + uint32_t _base_3 = {}; ///< Third part of the base field (63 - 95) + uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..8770b81 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief Possible overlying types of the segment descriptor. Allowing to discern between the major types, which + * result in different handling of the actual data contained in the descriptor. + */ + enum class segment_descriptor_type : uint8_t + { + SYSTEM_SEGMENT, ///< The segment is of type system, is distinguished by the Descriptor Type field in the Access + ///< Byte. Can be further distinguised to specific system segment types using the Type Field in the + ///< Access Byte. + DATA_SEGMENT, ///< The segment is of type data, is is distinguished by the Descriptor Type field in the Access + ///< Byte and the first bit of the Type Field in the Access Byte. Can be further distinguised to + ///< specific data segment types using the the remaining bits in the Type Field in the Access Byte. + CODE_SEGMENT, ///< The segment is of type code, is is distinguished by the Descriptor Type field in + ///< the Access Byte and the first bit of the Type Field in the Access Byte. Can be + ///< further distinguised to specific data segment types using the the remaining bits in + ///< the Type Field in the Access Byte. + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..d4aa5e8 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief 64-bit task state segment + */ + struct [[gnu::packed]] task_state_segment + { + private: + uint32_t : 32; + uint64_t rsp0 = {}; + uint64_t rsp1 = {}; + uint64_t rsp2 = {}; + uint64_t : 64; + uint64_t ist1 = {}; + uint64_t ist2 = {}; + uint64_t ist3 = {}; + uint64_t ist4 = {}; + uint64_t ist5 = {}; + uint64_t ist6 = {}; + uint64_t ist7 = {}; + uint64_t : 64; + uint16_t : 16; + uint16_t io_map_base_address = {}; + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp new file mode 100644 index 0000000..59adc13 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp @@ -0,0 +1,88 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP + +#include + +namespace teachos::arch::context_switching::syscall +{ + /** + * @brief Possible syscall implementation that should actually be called. + * + * @note Attempts to reflect the Linux interface partially. See https://filippo.io/linux-syscall-table/ for more + * information. + */ + enum class type : uint64_t + { + WRITE = 1U, ///< Loads the arg_0 parameter as an address pointing to a const char array, which will then be printed + ///< onto the VGA buffer screen. + EXPAND_HEAP = 2U, /// Expands the User Heap by additonally mapping 100 KiB of virtual page memory. Ignores the + /// parameters and uses them as out parameters instead, where arg_0 is the start of the newly + /// mapped heap area and arg_1 is the size of the entire area. Can be less than 100 KiB if less + /// space remains. + ASSERT = 3U, /// Loads the arg_0 parameter as a boolean which needs to be true or it will print the message in + /// arg_1 parameter onto the VGA buffer screen, keep it as a nullptr if it shouldn't print anything + /// and then it halts the further execution of the application. + }; + + /** + * @brief Possible error codes that can be returned by the different syscall methods called depending on the type + * enum. + */ + enum class error : uint8_t + { + OK = 0U, ///< No error occured in syscall. + OUT_OF_MEMORY = 1U, ///< Expanding heap failed because we have run out of mappable virtual address space. + }; + + /** + * @brief Allows to convert the error enum type into a boolean directly. Where any code besides 0 being no error, will + * return true. The remaining errors return true. + * + * @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; } + + /** + * @brief Maximum amount of arguments that can be passed to a syscall. Default value is 0 and arguments are only ever + * used depending on the actual enum type and if the method requires thoose parameters. + */ + struct arguments + { + uint64_t arg_0{}; ///< First optional paramter to the syscall representing the RDI register. + uint64_t arg_1{}; ///< Second optional paramter to the syscall representing the RSI register. + uint64_t arg_2{}; ///< Third optional paramter to the syscall representing the RDX register. + uint64_t arg_3{}; ///< Fourth optional paramter to the syscall representing the R10 register. + uint64_t arg_4{}; ///< Fifth optional paramter to the syscall representing the R8 register. + uint64_t arg_5{}; ///< Sixth optional paramter to the syscall representing the R9 register. + }; + + /** + * @brief Response of a systemcall always containin an error code, signaling if the syscall even succeeded or not. + * Additionally it may contain up to 6 return values in the values struct. + */ + struct response + { + error error_code; ///< Error code returned by the syscall. If it failed all the values will be 0. + arguments values = {}; ///< Optional return values of the syscall implementation. + }; + + /** + * @brief Calls the method associated with the given syscall number and passes the given optional arguments to it, + * over the RDI, RSI, RDX, R10, R8 and R9 register. + * + * @param syscall_number Syscall method that should be called. See enum values in type for possible implemented + * methods. + * @param args Optional arguments passable to the different syscall methods, called depending on the syscall_number. + * Not passing the required parameters to the method, will result in passing 0 instead, which might make the fail or + * not function correctly. + * @return The syscall implementation always returns a bool-convertable error code converting to true if the syscall + * failed or false if it didn't. Additionally it might pase additional values besides the error code, they will be set + * in the arguments struct. So the value can be read and used for further processing. + */ + [[gnu::section(".user_text")]] + auto syscall(type syscall_number, arguments args = {}) -> response; + +} // namespace teachos::arch::context_switching::syscall + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp new file mode 100644 index 0000000..8cb468a --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP + +namespace teachos::arch::context_switching::syscall +{ + /** + * @brief Enables and sets up internal CPU registers to allow for syscall to function correctly and switch context + * temporarily back to the kernel level. + * + * @note Configures the Model Specific Register required by syscall (LSTAR, FMASK, STAR) with the correct values so + * that the syscall_handler is called and sets the System Call Extension bit on the EFER flags to allow for syscall + * to be used. + */ + auto enable_syscall() -> void; + +} // namespace teachos::arch::context_switching::syscall + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp new file mode 100644 index 0000000..2e7bcd1 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP + +#include + +namespace teachos::arch::context_switching::syscall +{ + /** + * @brief Handler for SYSCALL instruction. Calls a specific implementation based + * on the register RAX. + * + * @return Returns with LEAVE, SYSRETQ + */ + auto syscall_handler() -> void; + +} // namespace teachos::arch::context_switching::syscall + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP diff --git a/arch/x86_64/pre/include/arch/exception_handling/assert.hpp b/arch/x86_64/pre/include/arch/exception_handling/assert.hpp new file mode 100644 index 0000000..1286768 --- /dev/null +++ b/arch/x86_64/pre/include/arch/exception_handling/assert.hpp @@ -0,0 +1,17 @@ +#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP +#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP + +namespace teachos::arch::exception_handling +{ + /** + * @brief Assert a condition to be true, if not do not continue + * execution of the code and print the given message to screen. + * + * @param condition Condition we want to be true or else halt execution. + * @param message Message that should be printed before halting the execution if the condition is not met. + */ + auto assert(bool condition, char const * message) -> void; + +} // namespace teachos::arch::exception_handling + +#endif // TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP diff --git a/arch/x86_64/pre/include/arch/exception_handling/panic.hpp b/arch/x86_64/pre/include/arch/exception_handling/panic.hpp new file mode 100644 index 0000000..6a2404c --- /dev/null +++ b/arch/x86_64/pre/include/arch/exception_handling/panic.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP +#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP + +namespace teachos::arch::exception_handling +{ + /** + * @brief Print the given kernel panic message and then halt the system. + * + * @param reason Reason to print before halting the system. + */ + [[noreturn]] auto panic(char const * reason) -> void; + + /** + * @brief Print the given kernel panic message started by a given prefix and then halt the system. + * + * @param prefix Prefix to print before printing the reason. + * @param reason Reason to print before halting the system. + */ + [[noreturn]] auto panic(char const * prefix, char const * reason) -> void; + +} // namespace teachos::arch::exception_handling + +#endif // TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP diff --git a/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp b/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp new file mode 100644 index 0000000..15b35c1 --- /dev/null +++ b/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -0,0 +1,34 @@ +#ifndef TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP +#define TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP + +#include + +namespace teachos::arch::interrupt_handling +{ + /** + * @brief Represents the CPU state during an interrupt. + * + * Some interrupts push an error code, while others do not. The full list + * of which vector number contains the error code can be found here: https://wiki.osdev.org/Exceptions + */ + struct [[gnu::packed]] interrupt_frame + { + // uint64_t error_code; ///< Error code only pushed by some exceptions, therefore it is commented out. + uint64_t ip; ///< Instruction pointer at the time of the interrupt. + uint64_t cs; ///< Code segment selector indicating privilege level. + uint64_t flags; ///< CPU flags (RFLAGS) storing processor state. + uint64_t sp; ///< Stack pointer at the time of the interrupt. + uint64_t ss; ///< Stack segment selector, usually unused in 64-bit mode. + }; + + /** + * @brief Generic interrupt handler function. + * + * @param frame Pointer to the interrupt frame containing CPU state. + */ + [[gnu::interrupt]] + auto generic_interrupt_handler(interrupt_frame * frame) -> void; + +} // namespace teachos::arch::interrupt_handling + +#endif // TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp new file mode 100644 index 0000000..3c43304 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp @@ -0,0 +1,30 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +#include + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Far Pointer. Address to function located in another code segment. + */ + struct far_pointer + { + void (*function)(); ///< Address of the function we want to call. (0-63) + context_switching::interrupt_descriptor_table::segment_selector + selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79) + }; + + /** + * @brief Far call - A call to an instruction located in a different segment than the current code segment but at the + * same privilege level. + * + * @param pointer 64-bit operand size far pointer that we want to call. + */ + auto call(far_pointer pointer) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp new file mode 100644 index 0000000..68b950d --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/gdtr.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP + +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" + +#include +#include + +namespace teachos::arch::kernel::cpu +{ + + /** + * @brief Returns the value in the GDTR register. + * + * @return Value of GDTR register. + */ + auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer; + + /** + * @brief Loads the global_descriptor_table_pointer into the global descriptor table register (GDTR). + */ + auto load_global_descriptor_table( + context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp new file mode 100644 index 0000000..cb800d0 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP + +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" + +#include +#include + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Returns the value in the IDTR register. + * + * @return Value of IDTR register. + */ + auto store_interrupt_descriptor_table() + -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer; + + /** + * @brief Loads the interrupt_descriptor_table_pointer into the interrupt descriptor table register (IDTR). + */ + auto load_interrupt_descriptor_table( + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp new file mode 100644 index 0000000..48707dc --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp @@ -0,0 +1,21 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Sets the interrupt flag (IF) in the EFLAGS register. + * This allows the processor to respond to maskable hardware interrupts. + */ + auto set_interrupt_flag() -> void; + + /** + * @brief Clears the interrupt flag (IF) in the EFLAGS register. + * This will stop the processor to respond to maskable hardware interrupts and needs to be done before changing the + * Interrupt Descriptor Table with lidt. + */ + auto clear_interrupt_flag() -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp new file mode 100644 index 0000000..99d6378 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp @@ -0,0 +1,64 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP + +#include +#include + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). + * + * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions + * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for + * more information. + */ + enum class efer_flags : uint64_t + { + SCE = 1UL << 0UL, ///< System Call Extensions. + LME = 1UL << 8UL, ///< Long Mode Enabled. + LMA = 1UL << 10UL, ///< Long Mode Active. + NXE = 1UL << 11UL, ///< No-Execute Enable. + SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. + LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. + FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. + TCE = 1UL << 15UL, ///< Translation Cache Extension. + }; + + /** + * @brief Reads a 64-bit from the Model-Specific Register (MSR). + * + * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper + * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. + * + * @param msr The address of the MSR to read. + * @return The 64-bit value read from the MSR. + */ + auto read_msr(uint32_t msr) -> uint64_t; + + /** + * @brief Writes a 64-bit value to a Model-Specific Register (MSR). + * + * @note This function writes a 64-bit value to the MSR specified by the given address. + * It splits the 64-bit value into two 32-bit parts and writes them using the + * `wrmsr` instruction. + * + * @param msr The address of the MSR to write to. + * @param new_value The 64-bit value to write to the MSR. + */ + auto write_msr(uint32_t msr, uint64_t new_value) -> void; + + /** + * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register + * (MSR). + * + * @note This function reads the current value of the EFER register, ORs the specified + * bit with the current value, and writes the updated value back to the EFER register. + * + * @param flag The flag to set in the EFER register. + */ + auto set_efer_bit(efer_flags flag) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp new file mode 100644 index 0000000..a236452 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/segment_register.hpp @@ -0,0 +1,97 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Clear all Data Segment registers (DS / ES / FS / GS). + */ + auto reload_data_segment_registers() -> void; + + /** + * @brief Updates the value of the Data Segment Register (DS), Extra Segment Register (ES), Thread-Local Storage + * Registers (FS / GS). + * + * @note The Stack Segment Register (SS) value should also be updated, but the value can not be directly set in + * comparsion to the other registers. This is the case because the register is used for stack management and can not + * be directly changed, instead this has to be done by a special instruction. Therefore + * validate_data_segment_registers should only be called after set_code_segment_register has been called as well. + * + * @param data_segment Value that should be loaded into the registers. + */ + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void; + + /** + * @brief Returns the Segment Selector pointing to the Code Segment that has been loaded into the Code Segment + * Register (CS). + * + * @note The CS register can not be directly changed, instead a Far Return has to be executed to change it + * + * @return Segment Selector pointing to the currently loaded Code Segment. + */ + [[gnu::section(".user_text")]] + auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector; + + /** + * @brief Validates that all Data Segment Registers (DS / ES / FS / GS / SS) are the same as the given Data Segment + * and asserts and stops the application if they are not. + * + * @note This is only the case after set_code_segment_register has been executed as well, because it makes a far + * return that updates the SS register. + * + * @param data_segment Value that should be loaded into all Data Segment Registers. + */ + auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) + -> void; + + /** + * @brief Validates that the Code Segment Register (CS) is the same as the given Code Segment + * and asserts and stops the application if they are not. + * + * @param code_segment Value that should be loaded into the Code Segment Register. + */ + auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) + -> void; + + /** + * @brief Simply forwards the call to validate_data_segment_registers and validate_code_segment_register and ensures + * that all Segment Registers, have been configured correctly. + * + * @note If all Segment Register have been set correctly the Context Switch using the set_code_segment_register method + * was successfull and the Privilege Level has been changed. + * + * @param data_segment Value that should be loaded into all Data Segment Registers. + * @param code_segment Value that should be loaded into the Code Segment Register. + */ + auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void; + + /** + * @brief Sets the value of the Code Segment Register (CS), this is achieved using a Far Return. + * + * @note The Far Return used by this method, will cause the context to switch, because we are changing from the + * current Code Segment and it's associated Privilege Level to another Code Segment. The given method will then be + * called in the new context and it should be possible to call validate_segment_registers, with the same values + * without assertions if the switch was successful. + * + * To achieve this Far Return we call IRETQ, which expects the stack to be defined a certain way to achieve that we: + * 1. Push the Data Segment Selector + * 2. Push the current Stack Pointer + * 3. Push Eflags + * 4. Push Code Segment Selector + * 5. Push Return Address + * + * @param data_segment Data Segment that should be loaded into the SS register. + * @param code_segment Code Segment that should be loaded into the CS register. + * @param address Function that we want to call in the new context created by the given Code Segment. + */ + [[gnu::naked]] + auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, + uint64_t address) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp new file mode 100644 index 0000000..7c856f1 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp @@ -0,0 +1,24 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP + +#include +#include + +namespace teachos::arch::kernel::cpu +{ + + /** + * @brief Returns the value in the LTR register. + * + * @return Value of LTR register. + */ + auto store_task_register() -> uint16_t; + + /** + * @brief Loads the gdt offset to the tss segment descriptor into the task register (TR). + */ + auto load_task_register(uint16_t gdt_offset) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/halt.hpp b/arch/x86_64/pre/include/arch/kernel/halt.hpp new file mode 100644 index 0000000..377acc0 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/halt.hpp @@ -0,0 +1,13 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP + +namespace teachos::arch::kernel +{ + /** + * @brief Halts the kernel execution, meaning any code after a call to this will not run anymore. + */ + extern "C" [[noreturn]] auto halt() -> void; + +} // namespace teachos::arch::kernel + +#endif // TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/main.hpp b/arch/x86_64/pre/include/arch/kernel/main.hpp new file mode 100644 index 0000000..a13e5f4 --- /dev/null +++ b/arch/x86_64/pre/include/arch/kernel/main.hpp @@ -0,0 +1,13 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP + +namespace teachos::arch::kernel +{ + /** + * @brief Initalizes the kernel system. + */ + auto main() -> void; + +} // namespace teachos::arch::kernel + +#endif // TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/pre/include/arch/memory/allocator/area_frame_allocator.hpp new file mode 100644 index 0000000..a86c9b7 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/allocator/area_frame_allocator.hpp @@ -0,0 +1,67 @@ +#ifndef TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP +#define TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP + +// #include "arch/memory/allocator/physical_frame.hpp" +// #include "arch/memory/multiboot/reader.hpp" + +#include + +namespace x86_64::memory +{ + /** + * @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; + + /** + * @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 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 x86_64::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/pre/include/arch/memory/allocator/concept.hpp b/arch/x86_64/pre/include/arch/memory/allocator/concept.hpp new file mode 100644 index 0000000..2d3f4ae --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/allocator/concept.hpp @@ -0,0 +1,21 @@ +#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 + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Frame allocator concept required for allocating and deallocating physical frames in memory. + */ + template + concept FrameAllocator = requires(T t, physical_frame const & a) { + { t.allocate_frame() } -> std::same_as>; + { t.deallocate_frame(a) } -> std::same_as; + }; + +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP diff --git a/arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp new file mode 100644 index 0000000..1ceb74d --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -0,0 +1,74 @@ +#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 + +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 + 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; + + /** + * @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, 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/pre/include/arch/memory/heap/bump_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/bump_allocator.hpp new file mode 100644 index 0000000..011f45c --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/heap/bump_allocator.hpp @@ -0,0 +1,48 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP + +#include "arch/memory/heap/heap_allocator.hpp" + +#include +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Simple heap allocator, which allocates linearly and leaks all allocated memory, because it does not really + * deallocate anything. + */ + struct bump_allocator : heap_allocator + { + /** + * @brief Constructor. + * + * @param heap_start Start of the allocatable heap area + * @param heap_end End of the allocatable heap area (Start + Size) + */ + bump_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start{heap_start} + , heap_end{heap_end} + , next{heap_start} + { + // Nothing to do + } + + auto allocate(std::size_t size) -> void * override; + + /** + * @copybrief heap_allocator::deallocate + * + * @note Simply does nothing, because this allocator leaks all memory + */ + auto deallocate(void * pointer) noexcept -> void override; + + private: + std::size_t heap_start; ///< Start of the allocatable heap area + std::size_t heap_end; ///< End of the allocatable heap area + std::atomic_uint64_t next; ///< Current address, which is the start of still unused allocatable heap area + }; + +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP diff --git a/arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp new file mode 100644 index 0000000..c98c130 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/heap/global_heap_allocator.hpp @@ -0,0 +1,118 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_GLOBAL_HEAP_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_GLOBAL_HEAP_ALLOCATOR_HPP + +#include "arch/memory/heap/heap_allocator.hpp" +#include "arch/memory/heap/user_heap_allocator.hpp" + +namespace teachos::arch::memory::heap +{ + /** + * @brief Possible types that should be constructed by the register_heap_allocator factory method. + * Creates the underlying heap allocator instance that is then used by all global allocations using new and delete + */ + enum class heap_allocator_type : uint8_t + { + NONE, ///< Don't use any heap allocation implementation, this will result in all calls of new and delte halting + ///< further execution of the kernel + BUMP, ///< Use the bump allocator as the heap allocation implementation, be aware that using this allocator leaks + ///< memory, because there is no delete implementation + LINKED_LIST ///< Use the linked list allocator as the heap implementation, recommended because it does not leak + ///< memory + }; + + /** + * @brief Global instance of a heap allocator implementation created by the factory method pattern @see + * https://refactoring.guru/design-patterns/factory-method for more information. + * + * @note Can only be registered once and only once the kernel and the heap part of the kernel has been remapped + * successfully. If the instance is created before than the device will abort, because it acceses unmapped memory + * areas. + */ + struct global_heap_allocator + { + /** + * @brief Registers the heap allocation implementation that should be used by the global heap allocator. + * Meaning all future calls to the global new or delete will be forwarded to the allocate and deallocate calls of + * the underlying heap allocation implementation + * + * @param new_type Type of the heap allocation implementation we want to instantiate + */ + static auto 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. + * Simply forwards the call to the allocate method of the registered heap_allocation implementation + * + * @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 *; + + /** + * @brief Deallocated all memory associated with the memory area starting from the given pointer address. + * Simply forwards the call to the deallocate method of the registered heap_allocation implementation + * + * @param pointer Previously allocated memory area, that should now be freed + */ + static auto kfree(void * pointer) noexcept -> void; + + /** + * @brief Allocates the given amount of memory and returns the pointer to the start of the allocatable memory area. + * Simply forwards the call to the allocate method of the registered heap_allocation implementation + * + * @param size Amount of bytes that should be allocated + * @return void* Pointer to the start of the allocatable memory area + */ + [[gnu::section(".user_text")]] + static auto malloc(std::size_t size) -> void *; + + /** + * @brief Deallocated all memory associated with the memory area starting from the given pointer address. + * Simply forwards the call to the deallocate method of the registered heap_allocation implementation + * + * @param pointer Previously allocated memory area, that should now be freed + */ + [[gnu::section(".user_text")]] + static auto 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 * + user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory + + /** + * @brief Either returns the previously registered heap allocated or halts further execution + * + * @return Reference to the registered kernel heap allocation + */ + static auto 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 &; + }; +} // namespace teachos::arch::memory::heap + +[[gnu::section(".user_text")]] +auto operator new(std::size_t size) -> void *; + +[[gnu::section(".user_text")]] +auto operator delete(void * pointer) noexcept -> void; + +[[gnu::section(".user_text")]] +auto operator delete(void * pointer, std::size_t size) noexcept -> void; + +[[gnu::section(".user_text")]] +auto operator new[](std::size_t size) -> void *; + +[[gnu::section(".user_text")]] +auto operator delete[](void * pointer) noexcept -> void; + +[[gnu::section(".user_text")]] +auto operator delete[](void * pointer, std::size_t size) noexcept -> void; + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_GLOBAL_HEAP_ALLOCATOR_HPP diff --git a/arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp new file mode 100644 index 0000000..420a1d3 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/heap/heap_allocator.hpp @@ -0,0 +1,45 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_HEAP_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_HEAP_ALLOCATOR_HPP + +#include + +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; + + /** + * @brief Heap allocator interface containing methods required to allocate and deallocate heap memory areas + */ + struct heap_allocator + { + /** + * @brief Virtual default destructor, created to ensure that if a pointer to this class is used and deleted, we will + * also call the derived base class destructor. Deleting a base class destructor that does not have a virtual + * destructor is undefined behaviour, because the derived class destructor originally instantiated with new is never + * called. This can cause potential memory leaks, because derived classes can not clean up their internal members as + * expected and instead simply leak them + */ + virtual ~heap_allocator() {} + + /** + * @brief Allocates the given amount of memory and returns the pointer to the start of the allocatable memory area + * + * @param size Amount of bytes that should be allocated + * @return void* Pointer to the start of the allocatable memory area + */ + virtual auto allocate(std::size_t size) -> void * = 0; + + /** + * @brief Deallocates all memory associated with the given pointer address. + * Simply deallocates the amount of memory created with the corresponding call to allocate + * + * @param pointer Previously allocated memory area, that should now be freed + */ + virtual auto deallocate(void * pointer) noexcept -> void = 0; + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_HEAP_ALLOCATOR_HPP diff --git a/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp new file mode 100644 index 0000000..bbbad19 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp @@ -0,0 +1,120 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP + +#include "arch/memory/heap/heap_allocator.hpp" +#include "arch/memory/heap/memory_block.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Sorted by address list of memory holes (free memory). Uses free holes itself to save the information, + * containing the size and pointer to the next hole. Resulting in a singly linked list. + */ + struct linked_list_allocator : heap_allocator + { + /** + * @brief Constructor. + * + * @param heap_start Start of the allocatable heap area + * @param heap_end End of the allocatable heap area (Start + Size) + */ + linked_list_allocator(std::size_t heap_start, std::size_t heap_end); + + /** + * @copybrief heap_allocator::allocate + * + * @note The specified size is used to find a free memory block with the exact same size, meaning we can remove that + * free memory block from the free list and simply return its address. Or it has to be big enough to hold the size + * and alteast enough memory for another free memory block entry (16 bytes). If the amount of memory of that free + * memory block is in between we cannot use it for our allocation, because we could only return it to the user, but + * the additional bytes, could not be used to create a free memory block. Additionaly the user couldn't know + * they received more memory than wanted. Therefore the memory would simply be unused and because it is neither + * allocated nor deallocated would never be indexed by the free memory list. We would therefore permanently loose + * that memory, to prevent that allocation into free memory blocks like that are impossible. + */ + auto allocate(std::size_t size) -> void * override; + + auto deallocate(void * pointer) noexcept -> void override; + + private: + /** + * @brief Returns the smallest allocatable block of heap memory. + * + * @return Smallest allocatable block of heap memory. + */ + auto constexpr 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. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to remove from the free list and return for the allocation. + * + * @return Previous start address of the memory block we removed, because it can now be used for the allocation. + */ + auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void *; + + /** + * @brief Splits the given free memory block into two, where the latter block keeps being free and the first + * part will be used for the allocation. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to split into a size part for the allocation and the rest for + * future allocations. + * @param size Size we want to allocate at the start of the free memory block. + * + * @return Previous start address of the memory block we just split, because it can now be used for the allocation. + */ + auto split_free_memory_block(memory_block * previous_block, memory_block * current_block, std::size_t size) + -> void *; + + /** + * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to remove from the free list and return for the allocation. + * @param new_block Replaces the current block with the given new block can be nullptr, meaning the free list will + * end here. + * + * @return Previous start address of the memory block we removed, because it can now be used for the allocation. + */ + auto replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void *; + + /** + * @brief Combines multiple free memory blocks into one if they are adjacent. + * + * @note The internal algorithm for recombination functions like this: + * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and + * we can therefore set the first entry to our newly created entry. This entry is created in the now deallocated + * memory area. + * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a + * new free memory block of the given size and set the previous next to our block and the next of our block to + * the current block. + * 3. If the current block is adjacent the start address of the newly created block stays the same, but the size + * increases by the amount in the current memory block header. After reading it we also clear the header. + * 4. If the previous block is adjacent the size of the previous block simply increases to include the given + * size as well. + * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of + * the region we are trying to deallocate has been freed before. Which would result in a double free therefore + * we halt the execution of the program. + * + * @param previous_block Free memory block before the block to deallocate in our heap memory. + * @param current_block Free memory block after the block to deallocate in our heap memory. + * @param pointer Block to deallocate. + * @param size Size of the block we want to deallocate. + */ + auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, + std::size_t size) -> void; + + memory_block * first; ///< First free entry in our memory. + kstd::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP diff --git a/arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp new file mode 100644 index 0000000..9d1fb02 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/heap/memory_block.hpp @@ -0,0 +1,39 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP + +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Block containing free memory, pointing to the next free hole (nullptr) if there is none. + * Forms a singly linked list of free memory blocks that we can callocate memory into. + */ + struct memory_block + { + /** + * @brief Constructor. Clears all memory from the place it was allocated until the end (address + + * size). + * + * @param size Amount of free memory of this specific hole. + * @param next Optional pointer to the next free memory. + */ + [[gnu::section(".user_text")]] + memory_block(std::size_t size, memory_block * next); + + /** + * @brief Destructor. Clears all internal memory. + * + * @note Used so the memory can be reused to construct other classes into, without having the old values. + * Required because we cannot call delete, because it causes "undefined reference to `sbrk`". + */ + [[gnu::section(".user_text")]] + ~memory_block(); + + std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the + ///< size variable and the pointer to the next hole. + memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP diff --git a/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp new file mode 100644 index 0000000..3b47f15 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp @@ -0,0 +1,149 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_ALLOCATOR_HPP + +#include "arch/memory/heap/memory_block.hpp" + +// #include +#include +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Sorted by address list of memory holes (free memory). Uses free holes itself to save the information, + * containing the size and pointer to the next hole. Resulting in a singly linked list. + */ + struct user_heap_allocator + { + /** + * @brief Constructor. + */ + user_heap_allocator() = default; + + /** + * @copybrief heap_allocator::allocate + * + * @note The specified size is used to find a free memory block with the exact same size, meaning we can remove that + * free memory block from the free list and simply return its address. Or it has to be big enough to hold the size + * and alteast enough memory for another free memory block entry (16 bytes). If the amount of memory of that free + * memory block is in between we cannot use it for our allocation, because we could only return it to the user, but + * the additional bytes, could not be used to create a free memory block. Additionaly the user couldn't know + * they received more memory than wanted. Therefore the memory would simply be unused and because it is neither + * allocated nor deallocated would never be indexed by the free memory list. We would therefore permanently loose + * that memory, to prevent that allocation into free memory blocks like that are impossible. + */ + [[gnu::section(".user_text")]] + auto allocate(std::size_t size) -> void *; + + /** + * @copybrief heap_allocator::deallocate + */ + [[gnu::section(".user_text")]] + auto deallocate(void * pointer) noexcept -> void; + + private: + /** + * @brief Returns the smallest allocatable block of heap memory. + * + * @return Smallest allocatable block of heap memory. + */ + [[gnu::section(".user_text")]] auto constexpr 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. + * + * @note Adjusts the link of the previous memory block to the new smaller remaining block. If the allocation used + * the complete block instead the previous block will point to the next block of the current memroy block that was + * used for the allocation. + * + * @return Allocated usable memory area. + */ + [[gnu::section(".user_text")]] auto + allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, std::size_t total_size) + -> std::optional; + + /** + * @brief Special functionality fo the user heap allocator. Which will result in it being expanded by a syscall with + * addtionally 100 KiB, which are mapped into the page table. Will always work until there is no physical memory + * left. + * + * @return Start of the newly with syscall allocated free memory block. Nullptr if the syscall failed. + */ + [[gnu::section(".user_text")]] auto expand_heap_if_full() -> memory_block *; + + /** + * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to remove from the free list and return for the allocation. + * + * @return Previous start address of the memory block we removed, because it can now be used for the allocation. + */ + [[gnu::section(".user_text")]] + auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void *; + + /** + * @brief Splits the given free memory block into two, where the latter block keeps being free and the first + * part will be used for the allocation. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to split into a size part for the allocation and the rest for + * future allocations. + * @param size Size we want to allocate at the start of the free memory block. + * + * @return Previous start address of the memory block we just split, because it can now be used for the allocation. + */ + [[gnu::section(".user_text")]] + auto split_free_memory_block(memory_block * previous_block, memory_block * current_block, std::size_t size) + -> void *; + + /** + * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to remove from the free list and return for the allocation. + * @param new_block Replaces the current block with the given new block can be nullptr, meaning the free list will + * end here. + * + * @return Previous start address of the memory block we removed, because it can now be used for the allocation. + */ + [[gnu::section(".user_text")]] + auto replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void *; + + /** + * @brief Combines multiple free memory blocks into one if they are adjacent. + * + * @note The internal algorithm for recombination functions like this: + * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and + * we can therefore set the first entry to our newly created entry. This entry is created in the now deallocated + * memory area. + * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a + * new free memory block of the given size and set the previous next to our block and the next of our block to + * the current block. + * 3. If the current block is adjacent the start address of the newly created block stays the same, but the size + * increases by the amount in the current memory block header. After reading it we also clear the header. + * 4. If the previous block is adjacent the size of the previous block simply increases to include the given + * size as well. + * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of + * the region we are trying to deallocate has been freed before. Which would result in a double free therefore + * we halt the execution of the program. + * + * @param previous_block Free memory block before the block to deallocate in our heap memory. + * @param current_block Free memory block after the block to deallocate in our heap memory. + * @param pointer Block to deallocate. + * @param size Size of the block we want to deallocate. + */ + [[gnu::section(".user_text")]] + auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, + std::size_t size) -> void; + + memory_block * first = {}; ///< First free entry in our memory. + kstd::mutex mutex = {}; ///< Mutex to ensure only one thread calls allocate or deallocate at once. + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_USER_HEAP_ALLOCATOR_HPP diff --git a/arch/x86_64/pre/include/arch/memory/main.hpp b/arch/x86_64/pre/include/arch/memory/main.hpp new file mode 100644 index 0000000..d51815f --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/main.hpp @@ -0,0 +1,30 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP + +#include "arch/memory/paging/page_entry.hpp" + +#include + +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/pre/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/pre/include/arch/memory/multiboot/elf_symbols_section.hpp new file mode 100644 index 0000000..348c159 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -0,0 +1,170 @@ +#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 +#include + +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>; + +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp new file mode 100644 index 0000000..c5464cb --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp @@ -0,0 +1,58 @@ +#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 "arch/memory/multiboot/elf_symbols_section.hpp" + +#include +#include +#include + +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. + multiboot2::elf_symbols; ///< 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. + // std::sp + // 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/pre/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp new file mode 100644 index 0000000..f68d8b6 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp @@ -0,0 +1,206 @@ +#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 +#include +#include + +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; + + /** + * @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; + + /** + * @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; + + /** + * @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 + 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 + 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 + 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 + 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 + 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/pre/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/pre/include/arch/memory/paging/inactive_page_table.hpp new file mode 100644 index 0000000..8d96740 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/inactive_page_table.hpp @@ -0,0 +1,39 @@ +#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/pre/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp new file mode 100644 index 0000000..3afb54b --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp @@ -0,0 +1,180 @@ +#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 +#include + +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 + 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 constexpr USER_SECTION_BASES = { + 0x102000, // .boot_bss (Contains statically allocated variables) + 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) + 0x217000, // .user_text (Contains the actual user code executed) + 0x21E000, // .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/pre/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/pre/include/arch/memory/paging/page_entry.hpp new file mode 100644 index 0000000..8147c5c --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/page_entry.hpp @@ -0,0 +1,121 @@ +#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 +#include + +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; + + /** + * @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/pre/include/arch/memory/paging/page_table.hpp b/arch/x86_64/pre/include/arch/memory/paging/page_table.hpp new file mode 100644 index 0000000..b972337 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/page_table.hpp @@ -0,0 +1,157 @@ +#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; + + /** + * @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 + 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/pre/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/pre/include/arch/memory/paging/temporary_page.hpp new file mode 100644 index 0000000..d0d7781 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/temporary_page.hpp @@ -0,0 +1,64 @@ +#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 + 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/pre/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp new file mode 100644 index 0000000..a6c8c39 --- /dev/null +++ b/arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp @@ -0,0 +1,91 @@ +#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 +#include +#include + +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>; + +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/pre/include/arch/user/main.hpp b/arch/x86_64/pre/include/arch/user/main.hpp new file mode 100644 index 0000000..c168a1f --- /dev/null +++ b/arch/x86_64/pre/include/arch/user/main.hpp @@ -0,0 +1,16 @@ +#ifndef TEACHOS_ARCH_X86_64_USER_MAIN_HPP +#define TEACHOS_ARCH_X86_64_USER_MAIN_HPP + +namespace teachos::arch::user +{ + /** + * @brief User Main method. If this method finishes there is no code left to run and the whole OS will shut down. + * Additionally this main method is executed at Ring 3 and accessing CPU Registers or Kernel level functionality can + * only be done over syscalls and not directly anymore. + */ + [[gnu::section(".user_text")]] + auto main() -> void; + +} // namespace teachos::arch::user + +#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp new file mode 100644 index 0000000..28f289c --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -0,0 +1,24 @@ +#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + gate_descriptor::gate_descriptor(uint128_t flags) + : _offset_1(flags) + , _selector(flags >> 19U, flags >> 16U) + , _ist(flags >> 32U) + , _flags(flags >> 40U) + , _offset_2(flags >> 48U) + { + // Nothing to do. + } + + gate_descriptor::gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset) + : _offset_1(offset) + , _selector(selector) + , _ist(ist) + , _flags(flags) + , _offset_2(offset >> 16U) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp new file mode 100644 index 0000000..d36a4c1 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp @@ -0,0 +1,17 @@ +#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + idt_flags::idt_flags(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto idt_flags::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } + + 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/pre/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 new file mode 100644 index 0000000..7aa0859 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -0,0 +1,53 @@ +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" + +#include "arch/exception_handling/assert.hpp" +#include "arch/interrupt_handling/generic_interrupt_handler.hpp" +#include "arch/kernel/cpu/idtr.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + namespace + { + /// @brief Amount of currently reserved interrupt indicies. + /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. + constexpr uint16_t RESERVED_INTERRUPT_COUNT = 256U; + + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table + { + interrupt_descriptor_table interrupt_descriptor_table{RESERVED_INTERRUPT_COUNT}; + + uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); + segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; + + for (std::size_t i = 0; i < interrupt_descriptor_table.size(); i++) + { + interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; + } + + return interrupt_descriptor_table; + } + } // namespace + + 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(); + return idt; + } + + auto update_interrupt_descriptor_table_register() -> void + { + decltype(auto) idt = get_or_create_interrupt_descriptor_table(); + + interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), + idt.data()}; + kernel::cpu::load_interrupt_descriptor_table(idt_pointer); + + auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); + arch::exception_handling::assert( + idt_pointer == stored_gdt_pointer, + "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..7bcbae6 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, + gate_descriptor * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp new file mode 100644 index 0000000..a70e75d --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + ist_offset::ist_offset(uint8_t index) + : _ist(index) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp new file mode 100644 index 0000000..27f0a3b --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -0,0 +1,15 @@ +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool + { + return (std::bitset<3U>{_flags} & other) == other; + } + + auto segment_selector::get_index() const -> uint16_t { return _index; } + + auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } + + segment_selector::operator uint16_t() const { return *reinterpret_cast(this); } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/main.cpp b/arch/x86_64/pre/src/context_switching/main.cpp new file mode 100644 index 0000000..9539428 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/main.cpp @@ -0,0 +1,63 @@ +#include "arch/context_switching/main.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall/syscall_enable.hpp" +#include "arch/kernel/cpu/call.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/segment_register.hpp" +#include "arch/kernel/cpu/tr.hpp" +#include "arch/user/main.hpp" + +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}; + 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}; + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + + auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + } // namespace + + auto initialize_descriptor_tables() -> descriptor_tables + { + static bool initalized = false; + + if (!initalized) + { + kernel::cpu::clear_interrupt_flag(); + + segment_descriptor_table::update_gdtr(); + interrupt_descriptor_table::update_interrupt_descriptor_table_register(); + + reload_gdtr(); + segment_descriptor_table::update_tss_register(); + + kernel::cpu::set_interrupt_flag(); + initalized = true; + } + + descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), + interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + return tables; + } + + auto switch_to_user_mode() -> void + { + syscall::enable_syscall(); + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); + } + + auto switch_context(interrupt_descriptor_table::segment_selector data_segment, + interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void + { + (void)initialize_descriptor_tables(); + kernel::cpu::set_data_segment_registers(data_segment); + kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); + } +} // namespace teachos::arch::context_switching diff --git a/arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp new file mode 100644 index 0000000..e31e021 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/access_byte.cpp @@ -0,0 +1,17 @@ +#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + access_byte::access_byte(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto access_byte::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } + + 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/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp new file mode 100644 index 0000000..e444a24 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/gdt_flags.cpp @@ -0,0 +1,20 @@ +#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) + : _limit_2(limit.to_ulong() >> 16U) + , _flags(flags) + { + // Nothing to do. + } + + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool + { + 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::operator|=(std::bitset<4U> other) -> void { _flags |= other.to_ulong(); } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..bbcee31 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -0,0 +1,109 @@ +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" + +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/gdtr.hpp" +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + namespace + { + 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}; + gdt_flags flags{gdt_flags::GRANULARITY, LIMIT}; + + access_level |= access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + flags |= gdt_flags::LONG_MODE; + access_level |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + access_level |= access_byte::WRITABLE; + } + + segment_descriptor_base const segment_descriptor_base{access_level, flags, BASE, LIMIT}; + return segment_descriptor_base; + } + + auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor_extension + { + uint64_t constexpr 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}; + segment_descriptor_extension const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), + TSS_LIMIT}; + return tss_descriptor; + } + + auto create_gdt() -> global_descriptor_table + { + segment_descriptor_base const null_segment{0}; + segment_descriptor_base const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor_base const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor_base const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor_base const user_data_segment = + 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(); + segment_descriptor_extension const tss_descriptor = create_tss_descriptor(tss); + + global_descriptor_table global_descriptor_table{null_segment, + kernel_code_segment, + kernel_data_segment, + user_code_segment, + user_data_segment, + tss_descriptor.get_first_gdt_entry(), + tss_descriptor.get_second_gdt_entry()}; + return global_descriptor_table; + } + } // namespace + + auto get_or_create_gdt() -> global_descriptor_table & + { + // Global Descriptor Table needs to be kept alive + static global_descriptor_table gdt = create_gdt(); + return gdt; + } + + auto update_gdtr() -> void + { + decltype(auto) gdt = get_or_create_gdt(); + + // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, + // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. + uint16_t gdt_size = static_cast((gdt.size() * sizeof(segment_descriptor_base)) - 1); + global_descriptor_table_pointer gdt_pointer{gdt_size, gdt.data()}; + kernel::cpu::load_global_descriptor_table(gdt_pointer); + + auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + arch::exception_handling::assert( + gdt_pointer == stored_gdt_pointer, + "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + } + + auto update_tss_register() -> void + { + decltype(auto) gdt = get_or_create_gdt(); + + // Load task state segment descriptor from the last element in the global descriptor table, done by calculating + // offset in bytes to the start of the segment descriptor (5 * 8) = 40 + uint16_t tss_selector = (gdt.size() * sizeof(segment_descriptor_base)) - sizeof(segment_descriptor_extension); + kernel::cpu::load_task_register(tss_selector); + + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + } + +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..79088b8 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -0,0 +1,11 @@ +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, uint64_t * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..04804d9 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp @@ -0,0 +1,38 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor_base::segment_descriptor_base(uint64_t flags) + : _limit_1(flags) + , _base_1(flags >> 16U) + , _access(flags >> 40U) + , _flag(flags >> 52U, flags >> 48U) + , _base_2(flags >> 56U) + { + // Nothing to do. + } + + segment_descriptor_base::segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, + std::bitset<20U> limit) + : _limit_1(limit.to_ulong()) + , _base_1(base) + , _access(access_byte) + , _flag(flags) + , _base_2(base >> 24U) + { + // Nothing to do + } + + auto segment_descriptor_base::get_segment_type() const -> segment_descriptor_type + { + if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) + { + return segment_descriptor_type::SYSTEM_SEGMENT; + } + return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; + } + + segment_descriptor_base::operator uint64_t() const { return *reinterpret_cast(this); } + +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/pre/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 new file mode 100644 index 0000000..a28ec9b --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp @@ -0,0 +1,24 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor_extension::segment_descriptor_extension(uint128_t flags) + : _base(flags) + , _base_3(flags >> 64U) + { + // Nothing to do. + } + + segment_descriptor_extension::segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, + std::bitset<20U> limit) + : _base(access_byte, flags, base, limit) + , _base_3(base >> 32U) + { + // Nothing to do + } + + 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; } + +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/syscall/main.cpp b/arch/x86_64/pre/src/context_switching/syscall/main.cpp new file mode 100644 index 0000000..b4ab468 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/syscall/main.cpp @@ -0,0 +1,35 @@ +#include "arch/context_switching/syscall/main.hpp" + +namespace teachos::arch::context_switching::syscall +{ + auto syscall(type syscall_number, arguments args) -> response + { + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(syscall_number) + : "memory"); + + asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); + asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); + asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); + asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); + asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); + asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); + + asm volatile("syscall"); + + arguments values{}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); + + error error_code{}; + asm volatile("mov %%al, %[output]" : [output] "=m"(error_code)); + + return {error_code, values}; + } + +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp new file mode 100644 index 0000000..3c43336 --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp @@ -0,0 +1,32 @@ +#include "arch/context_switching/syscall/syscall_enable.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/context_switching/syscall/syscall_handler.hpp" +#include "arch/kernel/cpu/msr.hpp" + +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}; + + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + + } // namespace + + auto enable_syscall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); + + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp new file mode 100644 index 0000000..84dbe5f --- /dev/null +++ b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp @@ -0,0 +1,118 @@ +#include "arch/context_switching/syscall/syscall_handler.hpp" + +#include "arch/context_switching/syscall/main.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/memory/main.hpp" +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::context_switching::syscall +{ + + namespace + { + auto write_to_vga_buffer(uint64_t buffer) -> response + { + video::vga::text::write(reinterpret_cast(buffer), + video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + return {error::OK}; + } + + auto expand_user_heap() -> response + { + static auto 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}}; + } + } // namespace + + auto syscall_handler() -> void + { + // Saving state of rcx and r11 because it is required by sysretq to function. + // Calls to other functions potentially overwrite these registers, because of + // callee saved calling convention. + uint64_t return_instruction_pointer, rflags = {}; + asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); + asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); + + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); + + // RAX is read last, because paired with our type enum, we can use it to check + // if the register has been written by the compiled code between executing the syscall + // and now. + asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); + + response result; + switch (static_cast(syscall_number)) + { + case type::WRITE: + result = write_to_vga_buffer(arg_0); + break; + case type::EXPAND_HEAP: + result = expand_user_heap(); + break; + case type::ASSERT: + teachos::arch::exception_handling::assert(arg_0, reinterpret_cast(arg_1)); + break; + default: + teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); + break; + } + + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(result.error_code) + : "memory"); + + asm volatile("mov %[input], %%rdi" + : /* no output from call */ + : [input] "m"(result.values.arg_0) + : "memory"); + asm volatile("mov %[input], %%rsi" + : /* no output from call */ + : [input] "m"(result.values.arg_1) + : "memory"); + asm volatile("mov %[input], %%rdx" + : /* no output from call */ + : [input] "m"(result.values.arg_2) + : "memory"); + asm volatile("mov %[input], %%r10" + : /* no output from call */ + : [input] "m"(result.values.arg_3) + : "memory"); + asm volatile("mov %[input], %%r8" + : /* no output from call */ + : [input] "m"(result.values.arg_4) + : "memory"); + asm volatile("mov %[input], %%r9" + : /* no output from call */ + : [input] "m"(result.values.arg_5) + : "memory"); + + asm volatile("mov %[input], %%rcx" + : /* no output from call */ + : [input] "m"(return_instruction_pointer) + : "memory"); + asm volatile("mov %[input], %%r11" + : /* no output from call */ + : [input] "m"(rflags) + : "memory"); + + // Additionally call leave, because x86 allocates stack space for the internal variables. If we do not clean up this + // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the + // method that originally called it, because the RIP has not been restored from the previous stack frame. + asm volatile("leave\n" + "sysretq"); + } + +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/exception_handling/abort.cpp b/arch/x86_64/pre/src/exception_handling/abort.cpp new file mode 100644 index 0000000..e12e4cb --- /dev/null +++ b/arch/x86_64/pre/src/exception_handling/abort.cpp @@ -0,0 +1,15 @@ +#include "arch/exception_handling/panic.hpp" + +#include + +namespace teachos::arch::exception_handling +{ + /** + * @brief Override for the newlib abort function. + * + * @note newlib defines @p ::abort as a weak symbol, thus allowing implementations to override it by simply providing + * 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"); } +} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/pre/src/exception_handling/assert.cpp b/arch/x86_64/pre/src/exception_handling/assert.cpp new file mode 100644 index 0000000..b2963de --- /dev/null +++ b/arch/x86_64/pre/src/exception_handling/assert.cpp @@ -0,0 +1,15 @@ +#include "arch/exception_handling/assert.hpp" + +#include "arch/exception_handling/panic.hpp" + +namespace teachos::arch::exception_handling +{ + auto assert(bool condition, char const * message) -> void + { + if (condition) + { + return; + } + panic("Assertion Violation: ", message); + } +} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/pre/src/exception_handling/panic.cpp b/arch/x86_64/pre/src/exception_handling/panic.cpp new file mode 100644 index 0000000..8e3802a --- /dev/null +++ b/arch/x86_64/pre/src/exception_handling/panic.cpp @@ -0,0 +1,22 @@ +#include "arch/exception_handling/panic.hpp" + +#include "arch/kernel/halt.hpp" +#include "arch/video/vga/text.hpp" + +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 * prefix, char const * reason) -> void + { + using video::vga::text::common_attributes::white_on_red; + + video::vga::text::newline(); + video::vga::text::write(prefix, white_on_red); + video::vga::text::write(reason, white_on_red); + + kernel::halt(); + }; +} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/pre/src/exception_handling/pure_virtual.cpp b/arch/x86_64/pre/src/exception_handling/pure_virtual.cpp new file mode 100644 index 0000000..67772f7 --- /dev/null +++ b/arch/x86_64/pre/src/exception_handling/pure_virtual.cpp @@ -0,0 +1,6 @@ +#include "arch/exception_handling/panic.hpp" + +extern "C" auto __cxa_pure_virtual() -> void +{ + teachos::arch::exception_handling::panic("Runtime", "Tried to call a pure virtual function!"); +} diff --git a/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp new file mode 100644 index 0000000..9d061a8 --- /dev/null +++ b/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp @@ -0,0 +1,13 @@ +#include "arch/interrupt_handling/generic_interrupt_handler.hpp" + +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::interrupt_handling +{ + auto generic_interrupt_handler(interrupt_frame * frame) -> void + { + (void)frame; + video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + } +} // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/pre/src/kernel/cpu/call.cpp b/arch/x86_64/pre/src/kernel/cpu/call.cpp new file mode 100644 index 0000000..98fa248 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/call.cpp @@ -0,0 +1,9 @@ +#include "arch/kernel/cpu/call.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto call(far_pointer pointer) -> void + { + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/gdtr.cpp b/arch/x86_64/pre/src/kernel/cpu/gdtr.cpp new file mode 100644 index 0000000..74a4e1c --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/gdtr.cpp @@ -0,0 +1,19 @@ +#include "arch/kernel/cpu/gdtr.hpp" + +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer + { + context_switching::segment_descriptor_table::global_descriptor_table_pointer current_value{}; + asm("sgdt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto load_global_descriptor_table( + context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void + { + asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/idtr.cpp b/arch/x86_64/pre/src/kernel/cpu/idtr.cpp new file mode 100644 index 0000000..7aa20c1 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/idtr.cpp @@ -0,0 +1,18 @@ +#include "arch/kernel/cpu/idtr.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_interrupt_descriptor_table() + -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer + { + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer current_value{}; + asm("sidt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto load_interrupt_descriptor_table( + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void + { + asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); + } +} // namespace teachos::arch::kernel::cpu 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..60a90a3 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/if.cpp @@ -0,0 +1,7 @@ +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/pre/src/kernel/cpu/msr.cpp b/arch/x86_64/pre/src/kernel/cpu/msr.cpp new file mode 100644 index 0000000..9c474a1 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/msr.cpp @@ -0,0 +1,31 @@ +#include "arch/kernel/cpu/msr.hpp" + +namespace teachos::arch::kernel::cpu +{ + namespace + { + auto constexpr IA32_EFER_ADDRESS = 0xC0000080; + } + + auto read_msr(uint32_t msr) -> uint64_t + { + uint32_t low, high; + asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); + return (static_cast(high) << 32) | low; + } + + auto write_msr(uint32_t msr, uint64_t value) -> void + { + uint32_t low = value; + uint32_t high = value >> 32; + asm volatile("wrmsr" + : /* no output from call */ + : "c"(msr), "a"(low), "d"(high)); + } + + auto set_efer_bit(efer_flags flag) -> void + { + auto const efer = read_msr(IA32_EFER_ADDRESS); + write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/segment_register.cpp b/arch/x86_64/pre/src/kernel/cpu/segment_register.cpp new file mode 100644 index 0000000..b08c9c4 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/segment_register.cpp @@ -0,0 +1,98 @@ +#include "arch/kernel/cpu/segment_register.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto reload_data_segment_registers() -> void + { + asm volatile("xor %%rax, %%rax\n" + "mov %%rax, %%ss\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + : /* no output from call */ + : /* no input to call */ + : "rax"); + } + + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void + { + asm volatile("xor %%rax, %%rax\n" + "mov %[input], %%ax\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + : /* no output from call */ + : [input] "m"(data_segment) + : "rax"); + } + + auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector + { + context_switching::interrupt_descriptor_table::segment_selector current_value{}; + asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); + return current_value; + } + + auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) + -> void + { + context_switching::interrupt_descriptor_table::segment_selector ss{}; + context_switching::interrupt_descriptor_table::segment_selector ds{}; + context_switching::interrupt_descriptor_table::segment_selector es{}; + context_switching::interrupt_descriptor_table::segment_selector fs{}; + context_switching::interrupt_descriptor_table::segment_selector gs{}; + + asm volatile( + "mov %%ss, %[ss_output]\n" + "mov %%ds, %[ds_output]\n" + "mov %%es, %[es_output]\n" + "mov %%fs, %[fs_output]\n" + "mov %%gs, %[gs_output]\n" + : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); + + auto result = (ss == ds && ss == es && ss == fs && ss == gs); + exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); + result = (ss == data_segment); + exception_handling::assert( + result, "[Segment Register] Expected Data Segment is not the same as the value in the Stack Segment register."); + } + + auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) + -> void + { + auto const cs = read_code_segment_register(); + exception_handling::assert( + cs == code_segment, + "[Segment Register] Expected Code Segment is not the same as the value in the Code Segment register."); + } + + auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void + { + validate_data_segment_registers(data_segment); + validate_code_segment_register(code_segment); + } + + auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, + uint64_t address) -> void + { + asm volatile("mov %%rsp, %%rax\n" + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" + "iretq\n" + : /* no output from call */ + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); + } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/tr.cpp b/arch/x86_64/pre/src/kernel/cpu/tr.cpp new file mode 100644 index 0000000..a435540 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/cpu/tr.cpp @@ -0,0 +1,16 @@ +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_task_register() -> uint16_t + { + uint16_t current_value{}; + asm("str %[output]" : [output] "=r"(current_value)); + return current_value; + } + + auto load_task_register(uint16_t gdt_offset) -> void + { + asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/main.cpp b/arch/x86_64/pre/src/kernel/main.cpp new file mode 100644 index 0000000..43b5f90 --- /dev/null +++ b/arch/x86_64/pre/src/kernel/main.cpp @@ -0,0 +1,71 @@ +#include "arch/kernel/main.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/context_switching/main.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/segment_register.hpp" +#include "arch/memory/heap/bump_allocator.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/memory/main.hpp" +#include "arch/memory/multiboot/reader.hpp" +#include "arch/stl/vector.hpp" +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::kernel +{ + auto stack_overflow_test(int count) -> int + { + int test[5000] = {}; + if (test[0] == 0xFFFF) + { + return count; + } + count = stack_overflow_test(count); + return count++; + } + + auto heap_test() -> void + { + auto test2 = new memory::multiboot::memory_information{}; + auto test3 = new memory::multiboot::memory_information{}; + auto test4 = *test2; + auto test5 = *test3; + test4.kernel_end = 5000; + test5.kernel_end = 3000; + auto test6 = test4.kernel_end; + auto test7 = test5.kernel_end; + auto test8 = memory::multiboot::read_multiboot2(); + if (test6 && test7 && test8.kernel_end) + { + video::vga::text::write("Heap test successful", video::vga::text::common_attributes::green_on_black); + } + test2->kernel_end = 2000; + test2->kernel_start = 1000; + test2->multiboot_start = 2000; + delete test2; + delete test3; + + auto test9 = new int(50); + delete test9; + } + + auto main() -> void + { + video::vga::text::clear(); + video::vga::text::cursor(false); + video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + + memory::initialize_memory_management(); + // stack_overflow_test(0); + + memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); + // heap_test(); + + auto address = memory::heap::global_heap_allocator::kmalloc(8U); + (void)address; + + context_switching::switch_to_user_mode(); + } +} // namespace teachos::arch::kernel diff --git a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp new file mode 100644 index 0000000..a5a1b49 --- /dev/null +++ b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp @@ -0,0 +1,85 @@ +#include "arch/memory/allocator/area_frame_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include +#include + +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 + { + // 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/pre/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp new file mode 100644 index 0000000..3cdf9c7 --- /dev/null +++ b/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp @@ -0,0 +1,34 @@ +#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 + { + 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/pre/src/memory/heap/bump_allocator.cpp b/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp new file mode 100644 index 0000000..525f45c --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp @@ -0,0 +1,54 @@ +#include "arch/memory/heap/bump_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include + +namespace teachos::arch::memory::heap +{ + namespace + { + template + auto saturating_add(T x, T y) -> T + requires std::is_unsigned_v + { + if (x > std::numeric_limits::max() - y) + { + return std::numeric_limits::max(); + } + T result = x + y; + return result; + } + } // namespace + + auto bump_allocator::allocate(std::size_t size) -> void * + { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); + // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time + // causing the value to differ and the calculation to have to be redone. + for (;;) + { + auto const alloc_end = saturating_add(alloc_start, size); + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); + // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another + // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation + // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. + auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); + if (updated) + { + return reinterpret_cast(alloc_start); + } + } + } + + auto bump_allocator::deallocate(void * pointer) noexcept -> void + { + if (pointer) + { + } + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp new file mode 100644 index 0000000..35cd623 --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp @@ -0,0 +1,135 @@ +#include "arch/memory/heap/global_heap_allocator.hpp" + +#include "arch/context_switching/syscall/main.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/segment_register.hpp" +#include "arch/memory/heap/bump_allocator.hpp" +#include "arch/memory/heap/linked_list_allocator.hpp" +#include "arch/memory/heap/user_heap_allocator.hpp" + +namespace teachos::arch::memory::heap +{ + namespace + { + constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."; + constexpr uint16_t KERNEL_CODE_INDEX = 1U; + + [[gnu::section(".user_text")]] + auto os_in_kernel_mode() -> bool + { + auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); + return cs.get_index() == KERNEL_CODE_INDEX; + } + } // namespace + + 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::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::free(void * pointer) noexcept -> void { user().deallocate(pointer); } + + auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void + { + exception_handling::assert(kernel_allocator_instance == nullptr, + "Calling register_heap_allocator_type can only be done once."); + + switch (new_type) + { + 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}; + 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}; + kernel_allocator_instance = &kernel_allocator; + break; + } + } + + [[gnu::section(".user_data")]] + static user_heap_allocator user_allocator{}; + user_allocator_instance = &user_allocator; + } + + auto global_heap_allocator::kernel() -> heap_allocator & + { + exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); + + return *kernel_allocator_instance; + } + + auto global_heap_allocator::user() -> user_heap_allocator & + { + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); + return *user_allocator_instance; + } +} // namespace teachos::arch::memory::heap + +auto operator new(std::size_t size) -> void * +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); +} + +auto operator delete(void * pointer) noexcept -> void +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} + +auto operator delete(void * pointer, std::size_t size) noexcept -> void +{ + (void)size; + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} + +auto operator new[](std::size_t size) -> void * +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); +} + +auto operator delete[](void * pointer) noexcept -> void +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} + +auto operator delete[](void * pointer, std::size_t size) noexcept -> void +{ + (void)size; + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} diff --git a/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp new file mode 100644 index 0000000..00ca366 --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp @@ -0,0 +1,177 @@ +#include "arch/memory/heap/linked_list_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) + : first(nullptr) + , mutex{kstd::mutex{}} + { + auto const heap_size = heap_end - heap_start; + exception_handling::assert( + heap_size > min_allocatable_size(), + "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " + "atleast one memory hole entry"); + first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + + auto linked_list_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + + previous = current; + current = current->next; + } + + exception_handling::panic("[Linked List Allocator] Out of memory"); + } + + auto linked_list_allocator::deallocate(void * pointer) noexcept -> void + { + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) + { + break; + } + + previous = current; + current = current->next; + } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); + } + + auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * + { + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto linked_list_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto linked_list_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // 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. + exception_handling::assert(previous_block == nullptr || + start_address >= + (reinterpret_cast(previous_block) + previous_block->size), + "[Linked List Allocator] Attempted double free detected"); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) + { + first = new_block; + return; + } + previous_block->next = new_block; + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/memory_block.cpp b/arch/x86_64/pre/src/memory/heap/memory_block.cpp new file mode 100644 index 0000000..bc97bd6 --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/memory_block.cpp @@ -0,0 +1,15 @@ +#include "arch/memory/heap/memory_block.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + memory_block::memory_block(std::size_t size, memory_block * next) + { + memset(static_cast(this), 0U, size); + this->size = size; + this->next = next; + } + + memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp new file mode 100644 index 0000000..427a68a --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp @@ -0,0 +1,200 @@ +#include "arch/memory/heap/user_heap_allocator.hpp" + +#include "arch/context_switching/syscall/main.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) + { + return memory.value(); + } + + previous = current; + current = current->next; + } + + current = expand_heap_if_full(); + + if (current != nullptr) + { + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) + { + return memory.value(); + } + } + + char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; + context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, + {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); + return nullptr; + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + { + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) + { + break; + } + + previous = current; + current = current->next; + } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); + } + + auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, + std::size_t total_size) -> std::optional + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + return std::nullopt; + } + + auto user_heap_allocator::expand_heap_if_full() -> memory_block * + { + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); + + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; + } + + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * + { + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // 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"; + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {previous_block == nullptr || + start_address >= (reinterpret_cast(previous_block) + previous_block->size), + reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) + { + first = new_block; + return; + } + previous_block->next = new_block; + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/main.cpp b/arch/x86_64/pre/src/memory/main.cpp new file mode 100644 index 0000000..2746a71 --- /dev/null +++ b/arch/x86_64/pre/src/memory/main.cpp @@ -0,0 +1,77 @@ +#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 + +namespace teachos::arch::memory +{ + namespace + { + static std::optional 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/pre/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp new file mode 100644 index 0000000..f5d126b --- /dev/null +++ b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp @@ -0,0 +1,13 @@ +#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/pre/src/memory/multiboot/reader.cpp b/arch/x86_64/pre/src/memory/multiboot/reader.cpp new file mode 100644 index 0000000..b05e6b3 --- /dev/null +++ b/arch/x86_64/pre/src/memory/multiboot/reader.cpp @@ -0,0 +1,135 @@ +#include "arch/memory/multiboot/reader.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "multiboot2/information.hpp" +// #include "arch/memory/multiboot/elf_symbols_section.hpp" +// #include "arch/memory/multiboot/info.hpp" + +#include +#include + +// namespace teachos::arch::memory::multiboot +// { +// namespace +// { +// template +// requires std::is_pointer::value +// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T +// { +// return reinterpret_cast(reinterpret_cast(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(&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(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(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(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/pre/src/memory/paging/active_page_table.cpp b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp new file mode 100644 index 0000000..0113869 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp @@ -0,0 +1,98 @@ +#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_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 + { + 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 + { + 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 + { + 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/pre/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp new file mode 100644 index 0000000..4e0610e --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp @@ -0,0 +1,20 @@ +#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/pre/src/memory/paging/page_entry.cpp b/arch/x86_64/pre/src/memory/paging/page_entry.cpp new file mode 100644 index 0000000..57045ca --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/page_entry.cpp @@ -0,0 +1,63 @@ +#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 + { + 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/pre/src/memory/paging/page_table.cpp b/arch/x86_64/pre/src/memory/paging/page_table.cpp new file mode 100644 index 0000000..eb11810 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/page_table.cpp @@ -0,0 +1,128 @@ +#include "arch/memory/paging/page_table.hpp" + +#include +#include +#include + +/* + * 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; + + 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::array 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 + { + auto const address = next_table_address(table_index); + if (address.has_value()) + { + return reinterpret_cast(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 + { + 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(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 + { + 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(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::type>(value); + value = static_cast(--new_value); + return value; + } +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/temporary_page.cpp b/arch/x86_64/pre/src/memory/paging/temporary_page.cpp new file mode 100644 index 0000000..8e73523 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/temporary_page.cpp @@ -0,0 +1,29 @@ +#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(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/pre/src/memory/paging/virtual_page.cpp b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp new file mode 100644 index 0000000..d374156 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp @@ -0,0 +1,33 @@ +#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/pre/src/user/main.cpp b/arch/x86_64/pre/src/user/main.cpp new file mode 100644 index 0000000..8b07e4a --- /dev/null +++ b/arch/x86_64/pre/src/user/main.cpp @@ -0,0 +1,35 @@ +#include "arch/user/main.hpp" + +#include "arch/context_switching/syscall/main.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" + +#include +#include +#include +#include + +namespace teachos::arch::user +{ + auto main() -> void + { + constexpr char syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + context_switching::syscall::syscall(context_switching::syscall::type::WRITE, + {reinterpret_cast(&syscall_message)}); + + // Test C++ standard library + std::array, 4> array_test = {std::atomic{5}, std::atomic{10}, + std::atomic{15}, std::atomic{20}}; + std::ranges::for_each(array_test, [](auto & item) { + auto value = item.load(); + uint8_t max_value = std::max(value, uint8_t{10}); + item.exchange(max_value + 2); + }); + + auto address = new uint64_t{10U}; + (void)address; + + for (;;) + { + } + } +} // namespace teachos::arch::user diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp deleted file mode 100644 index 28f289c..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - gate_descriptor::gate_descriptor(uint128_t flags) - : _offset_1(flags) - , _selector(flags >> 19U, flags >> 16U) - , _ist(flags >> 32U) - , _flags(flags >> 40U) - , _offset_2(flags >> 48U) - { - // Nothing to do. - } - - gate_descriptor::gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset) - : _offset_1(offset) - , _selector(selector) - , _ist(ist) - , _flags(flags) - , _offset_2(offset >> 16U) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp deleted file mode 100644 index d36a4c1..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - idt_flags::idt_flags(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto idt_flags::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } - - 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/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp deleted file mode 100644 index 7aa0859..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/interrupt_handling/generic_interrupt_handler.hpp" -#include "arch/kernel/cpu/idtr.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - namespace - { - /// @brief Amount of currently reserved interrupt indicies. - /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. - constexpr uint16_t RESERVED_INTERRUPT_COUNT = 256U; - - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table - { - interrupt_descriptor_table interrupt_descriptor_table{RESERVED_INTERRUPT_COUNT}; - - uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); - segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - - for (std::size_t i = 0; i < interrupt_descriptor_table.size(); i++) - { - interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; - } - - return interrupt_descriptor_table; - } - } // namespace - - 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(); - return idt; - } - - auto update_interrupt_descriptor_table_register() -> void - { - decltype(auto) idt = get_or_create_interrupt_descriptor_table(); - - interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), - idt.data()}; - kernel::cpu::load_interrupt_descriptor_table(idt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); - arch::exception_handling::assert( - idt_pointer == stored_gdt_pointer, - "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp deleted file mode 100644 index 7bcbae6..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - gate_descriptor * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp deleted file mode 100644 index a70e75d..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - ist_offset::ist_offset(uint8_t index) - : _ist(index) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp deleted file mode 100644 index 27f0a3b..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool - { - return (std::bitset<3U>{_flags} & other) == other; - } - - auto segment_selector::get_index() const -> uint16_t { return _index; } - - auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } - - segment_selector::operator uint16_t() const { return *reinterpret_cast(this); } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp deleted file mode 100644 index 9539428..0000000 --- a/arch/x86_64/src/context_switching/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "arch/context_switching/main.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall/syscall_enable.hpp" -#include "arch/kernel/cpu/call.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/kernel/cpu/tr.hpp" -#include "arch/user/main.hpp" - -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}; - 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}; - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - - auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } - } // namespace - - auto initialize_descriptor_tables() -> descriptor_tables - { - static bool initalized = false; - - if (!initalized) - { - kernel::cpu::clear_interrupt_flag(); - - segment_descriptor_table::update_gdtr(); - interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - - reload_gdtr(); - segment_descriptor_table::update_tss_register(); - - kernel::cpu::set_interrupt_flag(); - initalized = true; - } - - descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), - interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - return tables; - } - - auto switch_to_user_mode() -> void - { - syscall::enable_syscall(); - switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); - } - - auto switch_context(interrupt_descriptor_table::segment_selector data_segment, - interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void - { - (void)initialize_descriptor_tables(); - kernel::cpu::set_data_segment_registers(data_segment); - kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); - } -} // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp deleted file mode 100644 index e31e021..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - access_byte::access_byte(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto access_byte::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } - - 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/src/context_switching/segment_descriptor_table/gdt_flags.cpp deleted file mode 100644 index e444a24..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) - : _limit_2(limit.to_ulong() >> 16U) - , _flags(flags) - { - // Nothing to do. - } - - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool - { - 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::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/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp deleted file mode 100644 index bbcee31..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" - -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/gdtr.hpp" -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - namespace - { - 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}; - gdt_flags flags{gdt_flags::GRANULARITY, LIMIT}; - - access_level |= access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; - if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) - { - flags |= gdt_flags::LONG_MODE; - access_level |= access_byte::CODE_SEGMENT | access_byte::READABLE; - } - else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) - { - access_level |= access_byte::WRITABLE; - } - - segment_descriptor_base const segment_descriptor_base{access_level, flags, BASE, LIMIT}; - return segment_descriptor_base; - } - - auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor_extension - { - uint64_t constexpr 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}; - segment_descriptor_extension const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), - TSS_LIMIT}; - return tss_descriptor; - } - - auto create_gdt() -> global_descriptor_table - { - segment_descriptor_base const null_segment{0}; - segment_descriptor_base const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor_base const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor_base const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor_base const user_data_segment = - 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(); - segment_descriptor_extension const tss_descriptor = create_tss_descriptor(tss); - - global_descriptor_table global_descriptor_table{null_segment, - kernel_code_segment, - kernel_data_segment, - user_code_segment, - user_data_segment, - tss_descriptor.get_first_gdt_entry(), - tss_descriptor.get_second_gdt_entry()}; - return global_descriptor_table; - } - } // namespace - - auto get_or_create_gdt() -> global_descriptor_table & - { - // Global Descriptor Table needs to be kept alive - static global_descriptor_table gdt = create_gdt(); - return gdt; - } - - auto update_gdtr() -> void - { - decltype(auto) gdt = get_or_create_gdt(); - - // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, - // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. - uint16_t gdt_size = static_cast((gdt.size() * sizeof(segment_descriptor_base)) - 1); - global_descriptor_table_pointer gdt_pointer{gdt_size, gdt.data()}; - kernel::cpu::load_global_descriptor_table(gdt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); - arch::exception_handling::assert( - gdt_pointer == stored_gdt_pointer, - "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - } - - auto update_tss_register() -> void - { - decltype(auto) gdt = get_or_create_gdt(); - - // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // offset in bytes to the start of the segment descriptor (5 * 8) = 40 - uint16_t tss_selector = (gdt.size() * sizeof(segment_descriptor_base)) - sizeof(segment_descriptor_extension); - kernel::cpu::load_task_register(tss_selector); - - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp deleted file mode 100644 index 79088b8..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, uint64_t * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp deleted file mode 100644 index 04804d9..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - segment_descriptor_base::segment_descriptor_base(uint64_t flags) - : _limit_1(flags) - , _base_1(flags >> 16U) - , _access(flags >> 40U) - , _flag(flags >> 52U, flags >> 48U) - , _base_2(flags >> 56U) - { - // Nothing to do. - } - - segment_descriptor_base::segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, - std::bitset<20U> limit) - : _limit_1(limit.to_ulong()) - , _base_1(base) - , _access(access_byte) - , _flag(flags) - , _base_2(base >> 24U) - { - // Nothing to do - } - - auto segment_descriptor_base::get_segment_type() const -> segment_descriptor_type - { - if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) - { - return segment_descriptor_type::SYSTEM_SEGMENT; - } - return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; - } - - segment_descriptor_base::operator uint64_t() const { return *reinterpret_cast(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/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp deleted file mode 100644 index a28ec9b..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - segment_descriptor_extension::segment_descriptor_extension(uint128_t flags) - : _base(flags) - , _base_3(flags >> 64U) - { - // Nothing to do. - } - - segment_descriptor_extension::segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, - std::bitset<20U> limit) - : _base(access_byte, flags, base, limit) - , _base_3(base >> 32U) - { - // Nothing to do - } - - 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; } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp deleted file mode 100644 index b4ab468..0000000 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/context_switching/syscall/main.hpp" - -namespace teachos::arch::context_switching::syscall -{ - auto syscall(type syscall_number, arguments args) -> response - { - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "m"(syscall_number) - : "memory"); - - asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); - asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); - asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); - asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); - asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); - asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); - - asm volatile("syscall"); - - arguments values{}; - asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); - - error error_code{}; - asm volatile("mov %%al, %[output]" : [output] "=m"(error_code)); - - return {error_code, values}; - } - -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp deleted file mode 100644 index 3c43336..0000000 --- a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "arch/context_switching/syscall/syscall_enable.hpp" - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/syscall/syscall_handler.hpp" -#include "arch/kernel/cpu/msr.hpp" - -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}; - - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - - } // namespace - - auto enable_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp deleted file mode 100644 index 84dbe5f..0000000 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "arch/context_switching/syscall/syscall_handler.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/main.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::context_switching::syscall -{ - - namespace - { - auto write_to_vga_buffer(uint64_t buffer) -> response - { - video::vga::text::write(reinterpret_cast(buffer), - video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - return {error::OK}; - } - - auto expand_user_heap() -> response - { - static auto 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}}; - } - } // namespace - - auto syscall_handler() -> void - { - // Saving state of rcx and r11 because it is required by sysretq to function. - // Calls to other functions potentially overwrite these registers, because of - // callee saved calling convention. - uint64_t return_instruction_pointer, rflags = {}; - asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); - asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); - - uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; - asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); - - // RAX is read last, because paired with our type enum, we can use it to check - // if the register has been written by the compiled code between executing the syscall - // and now. - asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); - - response result; - switch (static_cast(syscall_number)) - { - case type::WRITE: - result = write_to_vga_buffer(arg_0); - break; - case type::EXPAND_HEAP: - result = expand_user_heap(); - break; - case type::ASSERT: - teachos::arch::exception_handling::assert(arg_0, reinterpret_cast(arg_1)); - break; - default: - teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); - break; - } - - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "m"(result.error_code) - : "memory"); - - asm volatile("mov %[input], %%rdi" - : /* no output from call */ - : [input] "m"(result.values.arg_0) - : "memory"); - asm volatile("mov %[input], %%rsi" - : /* no output from call */ - : [input] "m"(result.values.arg_1) - : "memory"); - asm volatile("mov %[input], %%rdx" - : /* no output from call */ - : [input] "m"(result.values.arg_2) - : "memory"); - asm volatile("mov %[input], %%r10" - : /* no output from call */ - : [input] "m"(result.values.arg_3) - : "memory"); - asm volatile("mov %[input], %%r8" - : /* no output from call */ - : [input] "m"(result.values.arg_4) - : "memory"); - asm volatile("mov %[input], %%r9" - : /* no output from call */ - : [input] "m"(result.values.arg_5) - : "memory"); - - asm volatile("mov %[input], %%rcx" - : /* no output from call */ - : [input] "m"(return_instruction_pointer) - : "memory"); - asm volatile("mov %[input], %%r11" - : /* no output from call */ - : [input] "m"(rflags) - : "memory"); - - // Additionally call leave, because x86 allocates stack space for the internal variables. If we do not clean up this - // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the - // method that originally called it, because the RIP has not been restored from the previous stack frame. - asm volatile("leave\n" - "sysretq"); - } - -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/exception_handling/abort.cpp b/arch/x86_64/src/exception_handling/abort.cpp deleted file mode 100644 index e12e4cb..0000000 --- a/arch/x86_64/src/exception_handling/abort.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::exception_handling -{ - /** - * @brief Override for the newlib abort function. - * - * @note newlib defines @p ::abort as a weak symbol, thus allowing implementations to override it by simply providing - * 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"); } -} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/src/exception_handling/assert.cpp deleted file mode 100644 index b2963de..0000000 --- a/arch/x86_64/src/exception_handling/assert.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/exception_handling/assert.hpp" - -#include "arch/exception_handling/panic.hpp" - -namespace teachos::arch::exception_handling -{ - auto assert(bool condition, char const * message) -> void - { - if (condition) - { - return; - } - panic("Assertion Violation: ", message); - } -} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/exception_handling/panic.cpp b/arch/x86_64/src/exception_handling/panic.cpp deleted file mode 100644 index 8e3802a..0000000 --- a/arch/x86_64/src/exception_handling/panic.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "arch/exception_handling/panic.hpp" - -#include "arch/kernel/halt.hpp" -#include "arch/video/vga/text.hpp" - -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 * prefix, char const * reason) -> void - { - using video::vga::text::common_attributes::white_on_red; - - video::vga::text::newline(); - video::vga::text::write(prefix, white_on_red); - video::vga::text::write(reason, white_on_red); - - kernel::halt(); - }; -} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/exception_handling/pure_virtual.cpp b/arch/x86_64/src/exception_handling/pure_virtual.cpp deleted file mode 100644 index 67772f7..0000000 --- a/arch/x86_64/src/exception_handling/pure_virtual.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "arch/exception_handling/panic.hpp" - -extern "C" auto __cxa_pure_virtual() -> void -{ - teachos::arch::exception_handling::panic("Runtime", "Tried to call a pure virtual function!"); -} diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp deleted file mode 100644 index 9d061a8..0000000 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/interrupt_handling/generic_interrupt_handler.hpp" - -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::interrupt_handling -{ - auto generic_interrupt_handler(interrupt_frame * frame) -> void - { - (void)frame; - video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - } -} // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp deleted file mode 100644 index 98fa248..0000000 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "arch/kernel/cpu/call.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto call(far_pointer pointer) -> void - { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/gdtr.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp deleted file mode 100644 index 74a4e1c..0000000 --- a/arch/x86_64/src/kernel/cpu/gdtr.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "arch/kernel/cpu/gdtr.hpp" - -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer - { - context_switching::segment_descriptor_table::global_descriptor_table_pointer current_value{}; - asm("sgdt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto load_global_descriptor_table( - context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void - { - asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp deleted file mode 100644 index 7aa20c1..0000000 --- a/arch/x86_64/src/kernel/cpu/idtr.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "arch/kernel/cpu/idtr.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_interrupt_descriptor_table() - -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer - { - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer current_value{}; - asm("sidt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto load_interrupt_descriptor_table( - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void - { - asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); - } -} // 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/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp deleted file mode 100644 index 9c474a1..0000000 --- a/arch/x86_64/src/kernel/cpu/msr.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "arch/kernel/cpu/msr.hpp" - -namespace teachos::arch::kernel::cpu -{ - namespace - { - auto constexpr IA32_EFER_ADDRESS = 0xC0000080; - } - - auto read_msr(uint32_t msr) -> uint64_t - { - uint32_t low, high; - asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); - return (static_cast(high) << 32) | low; - } - - auto write_msr(uint32_t msr, uint64_t value) -> void - { - uint32_t low = value; - uint32_t high = value >> 32; - asm volatile("wrmsr" - : /* no output from call */ - : "c"(msr), "a"(low), "d"(high)); - } - - auto set_efer_bit(efer_flags flag) -> void - { - auto const efer = read_msr(IA32_EFER_ADDRESS); - write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp deleted file mode 100644 index b08c9c4..0000000 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "arch/kernel/cpu/segment_register.hpp" - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto reload_data_segment_registers() -> void - { - asm volatile("xor %%rax, %%rax\n" - "mov %%rax, %%ss\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - : /* no output from call */ - : /* no input to call */ - : "rax"); - } - - auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void - { - asm volatile("xor %%rax, %%rax\n" - "mov %[input], %%ax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - : /* no output from call */ - : [input] "m"(data_segment) - : "rax"); - } - - auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector - { - context_switching::interrupt_descriptor_table::segment_selector current_value{}; - asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); - return current_value; - } - - auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) - -> void - { - context_switching::interrupt_descriptor_table::segment_selector ss{}; - context_switching::interrupt_descriptor_table::segment_selector ds{}; - context_switching::interrupt_descriptor_table::segment_selector es{}; - context_switching::interrupt_descriptor_table::segment_selector fs{}; - context_switching::interrupt_descriptor_table::segment_selector gs{}; - - asm volatile( - "mov %%ss, %[ss_output]\n" - "mov %%ds, %[ds_output]\n" - "mov %%es, %[es_output]\n" - "mov %%fs, %[fs_output]\n" - "mov %%gs, %[gs_output]\n" - : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); - - auto result = (ss == ds && ss == es && ss == fs && ss == gs); - exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); - result = (ss == data_segment); - exception_handling::assert( - result, "[Segment Register] Expected Data Segment is not the same as the value in the Stack Segment register."); - } - - auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) - -> void - { - auto const cs = read_code_segment_register(); - exception_handling::assert( - cs == code_segment, - "[Segment Register] Expected Code Segment is not the same as the value in the Code Segment register."); - } - - auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void - { - validate_data_segment_registers(data_segment); - validate_code_segment_register(code_segment); - } - - auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, - uint64_t address) -> void - { - asm volatile("mov %%rsp, %%rax\n" - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - "iretq\n" - : /* no output from call */ - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp deleted file mode 100644 index a435540..0000000 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_task_register() -> uint16_t - { - uint16_t current_value{}; - asm("str %[output]" : [output] "=r"(current_value)); - return current_value; - } - - auto load_task_register(uint16_t gdt_offset) -> void - { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp deleted file mode 100644 index 43b5f90..0000000 --- a/arch/x86_64/src/kernel/main.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "arch/kernel/main.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/main.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/memory/heap/bump_allocator.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/main.hpp" -#include "arch/memory/multiboot/reader.hpp" -#include "arch/stl/vector.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::kernel -{ - auto stack_overflow_test(int count) -> int - { - int test[5000] = {}; - if (test[0] == 0xFFFF) - { - return count; - } - count = stack_overflow_test(count); - return count++; - } - - auto heap_test() -> void - { - auto test2 = new memory::multiboot::memory_information{}; - auto test3 = new memory::multiboot::memory_information{}; - auto test4 = *test2; - auto test5 = *test3; - test4.kernel_end = 5000; - test5.kernel_end = 3000; - auto test6 = test4.kernel_end; - auto test7 = test5.kernel_end; - auto test8 = memory::multiboot::read_multiboot2(); - if (test6 && test7 && test8.kernel_end) - { - video::vga::text::write("Heap test successful", video::vga::text::common_attributes::green_on_black); - } - test2->kernel_end = 2000; - test2->kernel_start = 1000; - test2->multiboot_start = 2000; - delete test2; - delete test3; - - auto test9 = new int(50); - delete test9; - } - - auto main() -> void - { - video::vga::text::clear(); - video::vga::text::cursor(false); - video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - - memory::initialize_memory_management(); - // stack_overflow_test(0); - - memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); - // heap_test(); - - auto address = memory::heap::global_heap_allocator::kmalloc(8U); - (void)address; - - context_switching::switch_to_user_mode(); - } -} // namespace teachos::arch::kernel 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 -#include -#include - -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 - { - // 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/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 - { - 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/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp deleted file mode 100644 index 525f45c..0000000 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "arch/memory/heap/bump_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include - -namespace teachos::arch::memory::heap -{ - namespace - { - template - auto saturating_add(T x, T y) -> T - requires std::is_unsigned_v - { - if (x > std::numeric_limits::max() - y) - { - return std::numeric_limits::max(); - } - T result = x + y; - return result; - } - } // namespace - - auto bump_allocator::allocate(std::size_t size) -> void * - { - // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the - // exchange failed, becuase the value was not the expected one. - auto alloc_start = next.load(std::memory_order::relaxed); - // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time - // causing the value to differ and the calculation to have to be redone. - for (;;) - { - auto const alloc_end = saturating_add(alloc_start, size); - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); - // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another - // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation - // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. - auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); - if (updated) - { - return reinterpret_cast(alloc_start); - } - } - } - - auto bump_allocator::deallocate(void * pointer) noexcept -> void - { - if (pointer) - { - } - } - -} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp deleted file mode 100644 index 35cd623..0000000 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "arch/memory/heap/global_heap_allocator.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/memory/heap/bump_allocator.hpp" -#include "arch/memory/heap/linked_list_allocator.hpp" -#include "arch/memory/heap/user_heap_allocator.hpp" - -namespace teachos::arch::memory::heap -{ - namespace - { - constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."; - constexpr uint16_t KERNEL_CODE_INDEX = 1U; - - [[gnu::section(".user_text")]] - auto os_in_kernel_mode() -> bool - { - auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); - return cs.get_index() == KERNEL_CODE_INDEX; - } - } // namespace - - 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::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::free(void * pointer) noexcept -> void { user().deallocate(pointer); } - - auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void - { - exception_handling::assert(kernel_allocator_instance == nullptr, - "Calling register_heap_allocator_type can only be done once."); - - switch (new_type) - { - 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}; - 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}; - kernel_allocator_instance = &kernel_allocator; - break; - } - } - - [[gnu::section(".user_data")]] - static user_heap_allocator user_allocator{}; - user_allocator_instance = &user_allocator; - } - - auto global_heap_allocator::kernel() -> heap_allocator & - { - exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); - - return *kernel_allocator_instance; - } - - auto global_heap_allocator::user() -> user_heap_allocator & - { - context_switching::syscall::syscall( - context_switching::syscall::type::ASSERT, - {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); - return *user_allocator_instance; - } -} // namespace teachos::arch::memory::heap - -auto operator new(std::size_t size) -> void * -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); - } - return teachos::arch::memory::heap::global_heap_allocator::malloc(size); -} - -auto operator delete(void * pointer) noexcept -> void -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} - -auto operator delete(void * pointer, std::size_t size) noexcept -> void -{ - (void)size; - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} - -auto operator new[](std::size_t size) -> void * -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); - } - return teachos::arch::memory::heap::global_heap_allocator::malloc(size); -} - -auto operator delete[](void * pointer) noexcept -> void -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} - -auto operator delete[](void * pointer, std::size_t size) noexcept -> void -{ - (void)size; - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp deleted file mode 100644 index 00ca366..0000000 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "arch/memory/heap/linked_list_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) - : first(nullptr) - , mutex{kstd::mutex{}} - { - auto const heap_size = heap_end - heap_start; - exception_handling::assert( - heap_size > min_allocatable_size(), - "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " - "atleast one memory hole entry"); - first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - - auto linked_list_allocator::allocate(std::size_t size) -> void * - { - // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated - // block, to allow for deallocation without the need to call with the corresponding size - auto const total_size = size + sizeof(std::size_t); - mutex.lock(); - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - - previous = current; - current = current->next; - } - - exception_handling::panic("[Linked List Allocator] Out of memory"); - } - - auto linked_list_allocator::deallocate(void * pointer) noexcept -> void - { - mutex.lock(); - - // Read configured header size of the complete allocated block - auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); - auto const total_size = *reinterpret_cast(header_pointer); - - auto const start_address = reinterpret_cast(header_pointer); - auto const end_address = start_address + total_size; - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - // Current address of the free memory block now points to an address that is after our block to deallocate in heap - // memory space. - if (reinterpret_cast(current) >= end_address) - { - break; - } - - previous = current; - current = current->next; - } - - coalesce_free_memory_block(previous, current, header_pointer, total_size); - mutex.unlock(); - } - - auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) - -> void * - { - return replace_free_memory_block(previous_block, current_block, current_block->next); - } - - auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, - std::size_t size) -> void * - { - auto const end_address = reinterpret_cast(current_block) + size; - auto const new_block = - new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); - return replace_free_memory_block(previous_block, current_block, new_block); - } - - auto linked_list_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, - memory_block * new_block) -> void * - { - auto const start_address = reinterpret_cast(current_block); - // If we want to allocate into the first block that is before any other free block, then there exists no previous - // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. - if (previous_block == nullptr) - { - first = new_block; - } - else - { - previous_block->next = new_block; - } - current_block->~memory_block(); - return reinterpret_cast(start_address); - } - - auto linked_list_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, - void * pointer, std::size_t size) -> void - { - auto const start_address = reinterpret_cast(pointer); - auto const end_address = start_address + size; - - // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free - // memory block that is placed in between the previous and next block. - auto block_size = size; - auto next_block = current_block; - - // If the block we want to deallocate is before another free block and we can therefore combine both into one. - // This is done by deleting the current free block and creating a new block at the start address of the block to - // deallocate with both the size of the block to deallcoate and the free block next to it. - if (end_address == reinterpret_cast(current_block)) - { - block_size += current_block->size; - next_block = current_block->next; - current_block->~memory_block(); - } - - // If the block we want to deallocate is behind another free block and we can therefore combine both into one. - // This is done by simply changin the size of the previous block to include the size of the block to deallocate. - // This is done, because the previous block might still be referencered by the next field of other memory blocks. - if (previous_block != nullptr && - start_address == (reinterpret_cast(previous_block) + previous_block->size)) - { - block_size += previous_block->size; - - previous_block->size = block_size; - previous_block->next = next_block; - return; - } - - // 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. - exception_handling::assert(previous_block == nullptr || - start_address >= - (reinterpret_cast(previous_block) + previous_block->size), - "[Linked List Allocator] Attempted double free detected"); - - auto const new_block = new (pointer) memory_block(block_size, next_block); - // If we want to deallocate the first block that is before any other free block, then there exists no previous free - // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its - // next value. - if (previous_block == nullptr) - { - first = new_block; - return; - } - previous_block->next = new_block; - } - -} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp deleted file mode 100644 index bc97bd6..0000000 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/memory/heap/memory_block.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - memory_block::memory_block(std::size_t size, memory_block * next) - { - memset(static_cast(this), 0U, size); - this->size = size; - this->next = next; - } - - memory_block::~memory_block() { memset(static_cast(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/src/memory/heap/user_heap_allocator.cpp deleted file mode 100644 index 427a68a..0000000 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "arch/memory/heap/user_heap_allocator.hpp" - -#include "arch/context_switching/syscall/main.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - auto user_heap_allocator::allocate(std::size_t size) -> void * - { - // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated - // block, to allow for deallocation without the need to call with the corresponding size - auto const total_size = size + sizeof(std::size_t); - mutex.lock(); - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); - if (memory.has_value()) - { - return memory.value(); - } - - previous = current; - current = current->next; - } - - current = expand_heap_if_full(); - - if (current != nullptr) - { - auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); - if (memory.has_value()) - { - return memory.value(); - } - } - - char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; - context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, - {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); - return nullptr; - } - - auto user_heap_allocator::deallocate(void * pointer) noexcept -> void - { - mutex.lock(); - - // Read configured header size of the complete allocated block - auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); - auto const total_size = *reinterpret_cast(header_pointer); - - auto const start_address = reinterpret_cast(header_pointer); - auto const end_address = start_address + total_size; - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - // Current address of the free memory block now points to an address that is after our block to deallocate in heap - // memory space. - if (reinterpret_cast(current) >= end_address) - { - break; - } - - previous = current; - current = current->next; - } - - coalesce_free_memory_block(previous, current, header_pointer, total_size); - mutex.unlock(); - } - - auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, - std::size_t total_size) -> std::optional - { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - return std::nullopt; - } - - auto user_heap_allocator::expand_heap_if_full() -> memory_block * - { - auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); - - uint64_t const heap_start = result.values.arg_0; - uint64_t const heap_size = result.values.arg_1; - return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; - } - - auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) - -> void * - { - return replace_free_memory_block(previous_block, current_block, current_block->next); - } - - auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, - std::size_t size) -> void * - { - auto const end_address = reinterpret_cast(current_block) + size; - auto const new_block = - new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); - return replace_free_memory_block(previous_block, current_block, new_block); - } - - auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, - memory_block * new_block) -> void * - { - auto const start_address = reinterpret_cast(current_block); - // If we want to allocate into the first block that is before any other free block, then there exists no previous - // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. - if (previous_block == nullptr) - { - first = new_block; - } - else - { - previous_block->next = new_block; - } - current_block->~memory_block(); - return reinterpret_cast(start_address); - } - - auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, - void * pointer, std::size_t size) -> void - { - auto const start_address = reinterpret_cast(pointer); - auto const end_address = start_address + size; - - // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free - // memory block that is placed in between the previous and next block. - auto block_size = size; - auto next_block = current_block; - - // If the block we want to deallocate is before another free block and we can therefore combine both into one. - // This is done by deleting the current free block and creating a new block at the start address of the block to - // deallocate with both the size of the block to deallcoate and the free block next to it. - if (end_address == reinterpret_cast(current_block)) - { - block_size += current_block->size; - next_block = current_block->next; - current_block->~memory_block(); - } - - // If the block we want to deallocate is behind another free block and we can therefore combine both into one. - // This is done by simply changin the size of the previous block to include the size of the block to deallocate. - // This is done, because the previous block might still be referencered by the next field of other memory blocks. - if (previous_block != nullptr && - start_address == (reinterpret_cast(previous_block) + previous_block->size)) - { - block_size += previous_block->size; - - previous_block->size = block_size; - previous_block->next = next_block; - return; - } - - // 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"; - context_switching::syscall::syscall( - context_switching::syscall::type::ASSERT, - {previous_block == nullptr || - start_address >= (reinterpret_cast(previous_block) + previous_block->size), - reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); - - auto const new_block = new (pointer) memory_block(block_size, next_block); - // If we want to deallocate the first block that is before any other free block, then there exists no previous free - // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its - // next value. - if (previous_block == nullptr) - { - first = new_block; - return; - } - previous_block->next = new_block; - } - -} // namespace teachos::arch::memory::heap 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 - -namespace teachos::arch::memory -{ - namespace - { - static std::optional 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/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 b05e6b3..0000000 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "arch/memory/multiboot/reader.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/exception_handling/assert.hpp" -#include "multiboot2/information.hpp" -// #include "arch/memory/multiboot/elf_symbols_section.hpp" -// #include "arch/memory/multiboot/info.hpp" - -#include -#include - -// namespace teachos::arch::memory::multiboot -// { -// namespace -// { -// template -// requires std::is_pointer::value -// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T -// { -// return reinterpret_cast(reinterpret_cast(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(&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(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(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(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/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_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 - { - 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 - { - 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 - { - 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 - { - 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 -#include -#include - -/* - * 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; - - 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::array 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 - { - auto const address = next_table_address(table_index); - if (address.has_value()) - { - return reinterpret_cast(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 - { - 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(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 - { - 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(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::type>(value); - value = static_cast(--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(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/user/main.cpp b/arch/x86_64/src/user/main.cpp deleted file mode 100644 index 8b07e4a..0000000 --- a/arch/x86_64/src/user/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/user/main.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" - -#include -#include -#include -#include - -namespace teachos::arch::user -{ - auto main() -> void - { - constexpr char syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - context_switching::syscall::syscall(context_switching::syscall::type::WRITE, - {reinterpret_cast(&syscall_message)}); - - // Test C++ standard library - std::array, 4> array_test = {std::atomic{5}, std::atomic{10}, - std::atomic{15}, std::atomic{20}}; - std::ranges::for_each(array_test, [](auto & item) { - auto value = item.load(); - uint8_t max_value = std::max(value, uint8_t{10}); - item.exchange(max_value + 2); - }); - - auto address = new uint64_t{10U}; - (void)address; - - for (;;) - { - } - } -} // namespace teachos::arch::user -- cgit v1.2.3 From feac668578a35aac280b59d478a57b6937bb68da Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:39:43 +0000 Subject: docs: move files out of the way --- docs/arch/x86_64.rst | 9 --------- docs/arch/x86_64/boot.rst | 9 --------- docs/arch/x86_64/boot/pointers.rst | 5 ----- docs/arch/x86_64/context_switching.rst | 9 --------- .../x86_64/context_switching/interrupt_descriptor_table.rst | 9 --------- .../interrupt_descriptor_table/gate_descriptor.rst | 5 ----- .../interrupt_descriptor_table/idt_flags.rst | 5 ----- .../interrupt_descriptor_table copy.rst | 5 ----- .../interrupt_descriptor_table_pointer copy.rst | 5 ----- .../interrupt_descriptor_table/ist_offset.rst | 5 ----- .../interrupt_descriptor_table/segment_selector.rst | 5 ----- docs/arch/x86_64/context_switching/main.rst | 5 ----- .../x86_64/context_switching/segment_descriptor_table.rst | 9 --------- .../segment_descriptor_table/access_byte.rst | 5 ----- .../context_switching/segment_descriptor_table/gdt_flags.rst | 5 ----- .../segment_descriptor_table/global_descriptor_table.rst | 5 ----- .../global_descriptor_table_pointer.rst | 5 ----- .../segment_descriptor_table/segment_descriptor_base.rst | 5 ----- .../segment_descriptor_table/segment_descriptor_extension.rst | 5 ----- .../segment_descriptor_table/segment_descriptor_type.rst | 5 ----- .../segment_descriptor_table/task_state_segment.rst | 5 ----- docs/arch/x86_64/context_switching/syscall.rst | 9 --------- docs/arch/x86_64/context_switching/syscall/main.rst | 5 ----- docs/arch/x86_64/context_switching/syscall/syscall_enable.rst | 5 ----- .../arch/x86_64/context_switching/syscall/syscall_handler.rst | 5 ----- docs/arch/x86_64/exception_handling.rst | 9 --------- docs/arch/x86_64/exception_handling/assert.rst | 5 ----- docs/arch/x86_64/exception_handling/panic.rst | 5 ----- docs/arch/x86_64/interrupt_handling.rst | 9 --------- .../x86_64/interrupt_handling/generic_interrupt_handler.rst | 5 ----- docs/arch/x86_64/io.rst | 9 --------- docs/arch/x86_64/io/port_io.rst | 6 ------ docs/arch/x86_64/kernel.rst | 9 --------- docs/arch/x86_64/kernel/cpu.rst | 9 --------- docs/arch/x86_64/kernel/cpu/call.rst | 5 ----- docs/arch/x86_64/kernel/cpu/control_register.rst | 5 ----- docs/arch/x86_64/kernel/cpu/gdtr.rst | 5 ----- docs/arch/x86_64/kernel/cpu/idtr.rst | 5 ----- docs/arch/x86_64/kernel/cpu/if.rst | 5 ----- docs/arch/x86_64/kernel/cpu/msr.rst | 5 ----- docs/arch/x86_64/kernel/cpu/segment_register.rst | 5 ----- docs/arch/x86_64/kernel/cpu/tlb.rst | 5 ----- docs/arch/x86_64/kernel/cpu/tr.rst | 5 ----- docs/arch/x86_64/kernel/halt.rst | 5 ----- docs/arch/x86_64/kernel/main.rst | 5 ----- docs/arch/x86_64/memory.rst | 9 --------- docs/arch/x86_64/memory/allocator.rst | 9 --------- docs/arch/x86_64/memory/allocator/area_frame_allocator.rst | 5 ----- docs/arch/x86_64/memory/allocator/concept.rst | 5 ----- docs/arch/x86_64/memory/allocator/physical_frame.rst | 5 ----- docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst | 5 ----- docs/arch/x86_64/memory/cpu.rst | 9 --------- docs/arch/x86_64/memory/heap.rst | 9 --------- docs/arch/x86_64/memory/heap/bump_allocator.rst | 5 ----- docs/arch/x86_64/memory/heap/global_heap_allocator.rst | 5 ----- docs/arch/x86_64/memory/heap/heap_allocator.rst | 5 ----- docs/arch/x86_64/memory/heap/linked_list_allocator.rst | 5 ----- docs/arch/x86_64/memory/heap/memory_block.rst | 5 ----- docs/arch/x86_64/memory/heap/user_heap_allocator.rst | 5 ----- docs/arch/x86_64/memory/main.rst | 5 ----- docs/arch/x86_64/memory/multiboot.rst | 9 --------- docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst | 5 ----- docs/arch/x86_64/memory/multiboot/info.rst | 5 ----- docs/arch/x86_64/memory/multiboot/memory_map.rst | 5 ----- docs/arch/x86_64/memory/multiboot/reader.rst | 5 ----- docs/arch/x86_64/memory/paging.rst | 9 --------- docs/arch/x86_64/memory/paging/active_page_table.rst | 5 ----- docs/arch/x86_64/memory/paging/inactive_page_table.rst | 5 ----- docs/arch/x86_64/memory/paging/kernel_mapper.rst | 5 ----- docs/arch/x86_64/memory/paging/page_entry.rst | 5 ----- docs/arch/x86_64/memory/paging/page_table.rst | 5 ----- docs/arch/x86_64/memory/paging/temporary_page.rst | 5 ----- docs/arch/x86_64/memory/paging/virtual_page.rst | 5 ----- docs/arch/x86_64/stl.rst | 9 --------- docs/arch/x86_64/stl/container.rst | 5 ----- docs/arch/x86_64/stl/contiguous_pointer_iterator.rst | 5 ----- docs/arch/x86_64/stl/forward_value_iterator.rst | 5 ----- docs/arch/x86_64/stl/mutex.rst | 5 ----- docs/arch/x86_64/stl/shared_pointer.rst | 5 ----- docs/arch/x86_64/stl/stack.rst | 5 ----- docs/arch/x86_64/stl/unique_pointer.rst | 5 ----- docs/arch/x86_64/stl/vector.rst | 5 ----- docs/arch/x86_64/user.rst | 9 --------- docs/arch/x86_64/user/main.rst | 5 ----- docs/arch/x86_64/video.rst | 9 --------- docs/arch/x86_64/video/vga.rst | 9 --------- docs/arch/x86_64/video/vga/io.rst | 4 ---- docs/arch/x86_64/video/vga/text.rst | 5 ----- docs/conf.py | 2 +- docs/cross/memory.rst | 11 ----------- docs/cross/memory/asm_pointer.rst | 10 ---------- docs/pre/arch/x86_64.rst | 9 +++++++++ docs/pre/arch/x86_64/boot.rst | 9 +++++++++ docs/pre/arch/x86_64/boot/pointers.rst | 5 +++++ docs/pre/arch/x86_64/context_switching.rst | 9 +++++++++ .../x86_64/context_switching/interrupt_descriptor_table.rst | 9 +++++++++ .../interrupt_descriptor_table/gate_descriptor.rst | 5 +++++ .../interrupt_descriptor_table/idt_flags.rst | 5 +++++ .../interrupt_descriptor_table copy.rst | 5 +++++ .../interrupt_descriptor_table_pointer copy.rst | 5 +++++ .../interrupt_descriptor_table/ist_offset.rst | 5 +++++ .../interrupt_descriptor_table/segment_selector.rst | 5 +++++ docs/pre/arch/x86_64/context_switching/main.rst | 5 +++++ .../x86_64/context_switching/segment_descriptor_table.rst | 9 +++++++++ .../segment_descriptor_table/access_byte.rst | 5 +++++ .../context_switching/segment_descriptor_table/gdt_flags.rst | 5 +++++ .../segment_descriptor_table/global_descriptor_table.rst | 5 +++++ .../global_descriptor_table_pointer.rst | 5 +++++ .../segment_descriptor_table/segment_descriptor_base.rst | 5 +++++ .../segment_descriptor_table/segment_descriptor_extension.rst | 5 +++++ .../segment_descriptor_table/segment_descriptor_type.rst | 5 +++++ .../segment_descriptor_table/task_state_segment.rst | 5 +++++ docs/pre/arch/x86_64/context_switching/syscall.rst | 9 +++++++++ docs/pre/arch/x86_64/context_switching/syscall/main.rst | 5 +++++ .../arch/x86_64/context_switching/syscall/syscall_enable.rst | 5 +++++ .../arch/x86_64/context_switching/syscall/syscall_handler.rst | 5 +++++ docs/pre/arch/x86_64/exception_handling.rst | 9 +++++++++ docs/pre/arch/x86_64/exception_handling/assert.rst | 5 +++++ docs/pre/arch/x86_64/exception_handling/panic.rst | 5 +++++ docs/pre/arch/x86_64/interrupt_handling.rst | 9 +++++++++ .../x86_64/interrupt_handling/generic_interrupt_handler.rst | 5 +++++ docs/pre/arch/x86_64/io.rst | 9 +++++++++ docs/pre/arch/x86_64/io/port_io.rst | 6 ++++++ docs/pre/arch/x86_64/kernel.rst | 9 +++++++++ docs/pre/arch/x86_64/kernel/cpu.rst | 9 +++++++++ docs/pre/arch/x86_64/kernel/cpu/call.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/control_register.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/gdtr.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/idtr.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/if.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/msr.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/segment_register.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/tlb.rst | 5 +++++ docs/pre/arch/x86_64/kernel/cpu/tr.rst | 5 +++++ docs/pre/arch/x86_64/kernel/halt.rst | 5 +++++ docs/pre/arch/x86_64/kernel/main.rst | 5 +++++ docs/pre/arch/x86_64/memory.rst | 9 +++++++++ docs/pre/arch/x86_64/memory/allocator.rst | 9 +++++++++ .../pre/arch/x86_64/memory/allocator/area_frame_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/allocator/concept.rst | 5 +++++ docs/pre/arch/x86_64/memory/allocator/physical_frame.rst | 5 +++++ .../pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/cpu.rst | 9 +++++++++ docs/pre/arch/x86_64/memory/heap.rst | 9 +++++++++ docs/pre/arch/x86_64/memory/heap/bump_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/heap/heap_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/heap/memory_block.rst | 5 +++++ docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst | 5 +++++ docs/pre/arch/x86_64/memory/main.rst | 5 +++++ docs/pre/arch/x86_64/memory/multiboot.rst | 9 +++++++++ docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst | 5 +++++ docs/pre/arch/x86_64/memory/multiboot/info.rst | 5 +++++ docs/pre/arch/x86_64/memory/multiboot/memory_map.rst | 5 +++++ docs/pre/arch/x86_64/memory/multiboot/reader.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging.rst | 9 +++++++++ docs/pre/arch/x86_64/memory/paging/active_page_table.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging/page_entry.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging/page_table.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging/temporary_page.rst | 5 +++++ docs/pre/arch/x86_64/memory/paging/virtual_page.rst | 5 +++++ docs/pre/arch/x86_64/stl.rst | 9 +++++++++ docs/pre/arch/x86_64/stl/container.rst | 5 +++++ docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst | 5 +++++ docs/pre/arch/x86_64/stl/forward_value_iterator.rst | 5 +++++ docs/pre/arch/x86_64/stl/mutex.rst | 5 +++++ docs/pre/arch/x86_64/stl/shared_pointer.rst | 5 +++++ docs/pre/arch/x86_64/stl/stack.rst | 5 +++++ docs/pre/arch/x86_64/stl/unique_pointer.rst | 5 +++++ docs/pre/arch/x86_64/stl/vector.rst | 5 +++++ docs/pre/arch/x86_64/user.rst | 9 +++++++++ docs/pre/arch/x86_64/user/main.rst | 5 +++++ docs/pre/arch/x86_64/video.rst | 9 +++++++++ docs/pre/arch/x86_64/video/vga.rst | 9 +++++++++ docs/pre/arch/x86_64/video/vga/io.rst | 4 ++++ docs/pre/arch/x86_64/video/vga/text.rst | 5 +++++ docs/pre/cross/memory.rst | 11 +++++++++++ docs/pre/cross/memory/asm_pointer.rst | 10 ++++++++++ 181 files changed, 546 insertions(+), 546 deletions(-) delete mode 100644 docs/arch/x86_64.rst delete mode 100644 docs/arch/x86_64/boot.rst delete mode 100644 docs/arch/x86_64/boot/pointers.rst delete mode 100644 docs/arch/x86_64/context_switching.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst delete mode 100644 docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst delete mode 100644 docs/arch/x86_64/context_switching/main.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst delete mode 100644 docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst delete mode 100644 docs/arch/x86_64/context_switching/syscall.rst delete mode 100644 docs/arch/x86_64/context_switching/syscall/main.rst delete mode 100644 docs/arch/x86_64/context_switching/syscall/syscall_enable.rst delete mode 100644 docs/arch/x86_64/context_switching/syscall/syscall_handler.rst delete mode 100644 docs/arch/x86_64/exception_handling.rst delete mode 100644 docs/arch/x86_64/exception_handling/assert.rst delete mode 100644 docs/arch/x86_64/exception_handling/panic.rst delete mode 100644 docs/arch/x86_64/interrupt_handling.rst delete mode 100644 docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst delete mode 100644 docs/arch/x86_64/io.rst delete mode 100644 docs/arch/x86_64/io/port_io.rst delete mode 100644 docs/arch/x86_64/kernel.rst delete mode 100644 docs/arch/x86_64/kernel/cpu.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/call.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/control_register.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/gdtr.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/idtr.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/if.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/msr.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/segment_register.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/tlb.rst delete mode 100644 docs/arch/x86_64/kernel/cpu/tr.rst delete mode 100644 docs/arch/x86_64/kernel/halt.rst delete mode 100644 docs/arch/x86_64/kernel/main.rst delete mode 100644 docs/arch/x86_64/memory.rst delete mode 100644 docs/arch/x86_64/memory/allocator.rst delete mode 100644 docs/arch/x86_64/memory/allocator/area_frame_allocator.rst delete mode 100644 docs/arch/x86_64/memory/allocator/concept.rst delete mode 100644 docs/arch/x86_64/memory/allocator/physical_frame.rst delete mode 100644 docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst delete mode 100644 docs/arch/x86_64/memory/cpu.rst delete mode 100644 docs/arch/x86_64/memory/heap.rst delete mode 100644 docs/arch/x86_64/memory/heap/bump_allocator.rst delete mode 100644 docs/arch/x86_64/memory/heap/global_heap_allocator.rst delete mode 100644 docs/arch/x86_64/memory/heap/heap_allocator.rst delete mode 100644 docs/arch/x86_64/memory/heap/linked_list_allocator.rst delete mode 100644 docs/arch/x86_64/memory/heap/memory_block.rst delete mode 100644 docs/arch/x86_64/memory/heap/user_heap_allocator.rst delete mode 100644 docs/arch/x86_64/memory/main.rst delete mode 100644 docs/arch/x86_64/memory/multiboot.rst delete mode 100644 docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst delete mode 100644 docs/arch/x86_64/memory/multiboot/info.rst delete mode 100644 docs/arch/x86_64/memory/multiboot/memory_map.rst delete mode 100644 docs/arch/x86_64/memory/multiboot/reader.rst delete mode 100644 docs/arch/x86_64/memory/paging.rst delete mode 100644 docs/arch/x86_64/memory/paging/active_page_table.rst delete mode 100644 docs/arch/x86_64/memory/paging/inactive_page_table.rst delete mode 100644 docs/arch/x86_64/memory/paging/kernel_mapper.rst delete mode 100644 docs/arch/x86_64/memory/paging/page_entry.rst delete mode 100644 docs/arch/x86_64/memory/paging/page_table.rst delete mode 100644 docs/arch/x86_64/memory/paging/temporary_page.rst delete mode 100644 docs/arch/x86_64/memory/paging/virtual_page.rst delete mode 100644 docs/arch/x86_64/stl.rst delete mode 100644 docs/arch/x86_64/stl/container.rst delete mode 100644 docs/arch/x86_64/stl/contiguous_pointer_iterator.rst delete mode 100644 docs/arch/x86_64/stl/forward_value_iterator.rst delete mode 100644 docs/arch/x86_64/stl/mutex.rst delete mode 100644 docs/arch/x86_64/stl/shared_pointer.rst delete mode 100644 docs/arch/x86_64/stl/stack.rst delete mode 100644 docs/arch/x86_64/stl/unique_pointer.rst delete mode 100644 docs/arch/x86_64/stl/vector.rst delete mode 100644 docs/arch/x86_64/user.rst delete mode 100644 docs/arch/x86_64/user/main.rst delete mode 100644 docs/arch/x86_64/video.rst delete mode 100644 docs/arch/x86_64/video/vga.rst delete mode 100644 docs/arch/x86_64/video/vga/io.rst delete mode 100644 docs/arch/x86_64/video/vga/text.rst delete mode 100644 docs/cross/memory.rst delete mode 100644 docs/cross/memory/asm_pointer.rst create mode 100644 docs/pre/arch/x86_64.rst create mode 100644 docs/pre/arch/x86_64/boot.rst create mode 100644 docs/pre/arch/x86_64/boot/pointers.rst create mode 100644 docs/pre/arch/x86_64/context_switching.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst create mode 100644 docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst create mode 100644 docs/pre/arch/x86_64/context_switching/main.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst create mode 100644 docs/pre/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst create mode 100644 docs/pre/arch/x86_64/context_switching/syscall.rst create mode 100644 docs/pre/arch/x86_64/context_switching/syscall/main.rst create mode 100644 docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst create mode 100644 docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst create mode 100644 docs/pre/arch/x86_64/exception_handling.rst create mode 100644 docs/pre/arch/x86_64/exception_handling/assert.rst create mode 100644 docs/pre/arch/x86_64/exception_handling/panic.rst create mode 100644 docs/pre/arch/x86_64/interrupt_handling.rst create mode 100644 docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst create mode 100644 docs/pre/arch/x86_64/io.rst create mode 100644 docs/pre/arch/x86_64/io/port_io.rst create mode 100644 docs/pre/arch/x86_64/kernel.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/call.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/control_register.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/gdtr.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/idtr.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/if.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/msr.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/segment_register.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/tlb.rst create mode 100644 docs/pre/arch/x86_64/kernel/cpu/tr.rst create mode 100644 docs/pre/arch/x86_64/kernel/halt.rst create mode 100644 docs/pre/arch/x86_64/kernel/main.rst create mode 100644 docs/pre/arch/x86_64/memory.rst create mode 100644 docs/pre/arch/x86_64/memory/allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/allocator/concept.rst create mode 100644 docs/pre/arch/x86_64/memory/allocator/physical_frame.rst create mode 100644 docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/cpu.rst create mode 100644 docs/pre/arch/x86_64/memory/heap.rst create mode 100644 docs/pre/arch/x86_64/memory/heap/bump_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/heap/heap_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/heap/memory_block.rst create mode 100644 docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst create mode 100644 docs/pre/arch/x86_64/memory/main.rst create mode 100644 docs/pre/arch/x86_64/memory/multiboot.rst create mode 100644 docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst create mode 100644 docs/pre/arch/x86_64/memory/multiboot/info.rst create mode 100644 docs/pre/arch/x86_64/memory/multiboot/memory_map.rst create mode 100644 docs/pre/arch/x86_64/memory/multiboot/reader.rst create mode 100644 docs/pre/arch/x86_64/memory/paging.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/active_page_table.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/page_entry.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/page_table.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/temporary_page.rst create mode 100644 docs/pre/arch/x86_64/memory/paging/virtual_page.rst create mode 100644 docs/pre/arch/x86_64/stl.rst create mode 100644 docs/pre/arch/x86_64/stl/container.rst create mode 100644 docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst create mode 100644 docs/pre/arch/x86_64/stl/forward_value_iterator.rst create mode 100644 docs/pre/arch/x86_64/stl/mutex.rst create mode 100644 docs/pre/arch/x86_64/stl/shared_pointer.rst create mode 100644 docs/pre/arch/x86_64/stl/stack.rst create mode 100644 docs/pre/arch/x86_64/stl/unique_pointer.rst create mode 100644 docs/pre/arch/x86_64/stl/vector.rst create mode 100644 docs/pre/arch/x86_64/user.rst create mode 100644 docs/pre/arch/x86_64/user/main.rst create mode 100644 docs/pre/arch/x86_64/video.rst create mode 100644 docs/pre/arch/x86_64/video/vga.rst create mode 100644 docs/pre/arch/x86_64/video/vga/io.rst create mode 100644 docs/pre/arch/x86_64/video/vga/text.rst create mode 100644 docs/pre/cross/memory.rst create mode 100644 docs/pre/cross/memory/asm_pointer.rst diff --git a/docs/arch/x86_64.rst b/docs/arch/x86_64.rst deleted file mode 100644 index dc432f1..0000000 --- a/docs/arch/x86_64.rst +++ /dev/null @@ -1,9 +0,0 @@ -x86_64 -====== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - x86_64/* \ No newline at end of file diff --git a/docs/arch/x86_64/boot.rst b/docs/arch/x86_64/boot.rst deleted file mode 100644 index 8be2a57..0000000 --- a/docs/arch/x86_64/boot.rst +++ /dev/null @@ -1,9 +0,0 @@ -Boot Information Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - boot/* \ No newline at end of file diff --git a/docs/arch/x86_64/boot/pointers.rst b/docs/arch/x86_64/boot/pointers.rst deleted file mode 100644 index 3ec626a..0000000 --- a/docs/arch/x86_64/boot/pointers.rst +++ /dev/null @@ -1,5 +0,0 @@ -Boot Information Structure -======================= - -.. doxygenfile:: arch/x86_64/include/arch/boot/pointers.hpp - diff --git a/docs/arch/x86_64/context_switching.rst b/docs/arch/x86_64/context_switching.rst deleted file mode 100644 index c3b3b03..0000000 --- a/docs/arch/x86_64/context_switching.rst +++ /dev/null @@ -1,9 +0,0 @@ -Context Switching Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - context_switching/* \ No newline at end of file diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst deleted file mode 100644 index dd6e478..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table.rst +++ /dev/null @@ -1,9 +0,0 @@ -Interrupt Descriptor Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - interrupt_descriptor_table/* diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst deleted file mode 100644 index 29e7586..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Gate Descriptor -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp - diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst deleted file mode 100644 index 60e8c37..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Descriptor Flags -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp - diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst deleted file mode 100644 index a2b8997..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Descriptor Table -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp - diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst deleted file mode 100644 index 3a8c259..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Descriptor Table Pointer -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp - diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst deleted file mode 100644 index ddba6ee..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Stack Table Offset -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp - diff --git a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst b/docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst deleted file mode 100644 index 2da142e..0000000 --- a/docs/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst +++ /dev/null @@ -1,5 +0,0 @@ -Segment Selector -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp - diff --git a/docs/arch/x86_64/context_switching/main.rst b/docs/arch/x86_64/context_switching/main.rst deleted file mode 100644 index e9e8a35..0000000 --- a/docs/arch/x86_64/context_switching/main.rst +++ /dev/null @@ -1,5 +0,0 @@ -Context Switching Main -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/main.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table.rst deleted file mode 100644 index 449622d..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table.rst +++ /dev/null @@ -1,9 +0,0 @@ -Segment Descriptor Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - segment_descriptor_table/* diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst deleted file mode 100644 index f2e7d67..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst +++ /dev/null @@ -1,5 +0,0 @@ -Access Byte -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst deleted file mode 100644 index faa2ffc..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst +++ /dev/null @@ -1,5 +0,0 @@ -Global Descriptor Table Flags -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst deleted file mode 100644 index 35403db..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst +++ /dev/null @@ -1,5 +0,0 @@ -Global Descriptor Table -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst deleted file mode 100644 index 41ceffd..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst +++ /dev/null @@ -1,5 +0,0 @@ -Global Descriptor Table Pointer -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst deleted file mode 100644 index 952ab2a..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst +++ /dev/null @@ -1,5 +0,0 @@ -Segment Descriptor Base (32-bit) -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst deleted file mode 100644 index 874d1cb..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst +++ /dev/null @@ -1,5 +0,0 @@ -Segment Descriptor Extension (64-bit) -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst deleted file mode 100644 index e45b0a5..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst +++ /dev/null @@ -1,5 +0,0 @@ -Segment Descriptor Type -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp - diff --git a/docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst b/docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst deleted file mode 100644 index 731d7bb..0000000 --- a/docs/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst +++ /dev/null @@ -1,5 +0,0 @@ -Task State Segment -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp - diff --git a/docs/arch/x86_64/context_switching/syscall.rst b/docs/arch/x86_64/context_switching/syscall.rst deleted file mode 100644 index 28acf28..0000000 --- a/docs/arch/x86_64/context_switching/syscall.rst +++ /dev/null @@ -1,9 +0,0 @@ -System Call Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - syscall/* diff --git a/docs/arch/x86_64/context_switching/syscall/main.rst b/docs/arch/x86_64/context_switching/syscall/main.rst deleted file mode 100644 index 6be577b..0000000 --- a/docs/arch/x86_64/context_switching/syscall/main.rst +++ /dev/null @@ -1,5 +0,0 @@ -System Call Main -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/syscall/main.hpp - diff --git a/docs/arch/x86_64/context_switching/syscall/syscall_enable.rst b/docs/arch/x86_64/context_switching/syscall/syscall_enable.rst deleted file mode 100644 index e9162f1..0000000 --- a/docs/arch/x86_64/context_switching/syscall/syscall_enable.rst +++ /dev/null @@ -1,5 +0,0 @@ -System Call Configuration -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp - diff --git a/docs/arch/x86_64/context_switching/syscall/syscall_handler.rst b/docs/arch/x86_64/context_switching/syscall/syscall_handler.rst deleted file mode 100644 index 0e86780..0000000 --- a/docs/arch/x86_64/context_switching/syscall/syscall_handler.rst +++ /dev/null @@ -1,5 +0,0 @@ -System Call Handler -======================= - -.. doxygenfile:: arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp - diff --git a/docs/arch/x86_64/exception_handling.rst b/docs/arch/x86_64/exception_handling.rst deleted file mode 100644 index 3bf2770..0000000 --- a/docs/arch/x86_64/exception_handling.rst +++ /dev/null @@ -1,9 +0,0 @@ -Exception Handling Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - exception_handling/* \ No newline at end of file diff --git a/docs/arch/x86_64/exception_handling/assert.rst b/docs/arch/x86_64/exception_handling/assert.rst deleted file mode 100644 index 053cf66..0000000 --- a/docs/arch/x86_64/exception_handling/assert.rst +++ /dev/null @@ -1,5 +0,0 @@ -Exception Handling Assertion -======================= - -.. doxygenfile:: arch/x86_64/include/arch/exception_handling/assert.hpp - diff --git a/docs/arch/x86_64/exception_handling/panic.rst b/docs/arch/x86_64/exception_handling/panic.rst deleted file mode 100644 index 50b6284..0000000 --- a/docs/arch/x86_64/exception_handling/panic.rst +++ /dev/null @@ -1,5 +0,0 @@ -Exception Handling Panic -======================= - -.. doxygenfile:: arch/x86_64/include/arch/exception_handling/panic.hpp - diff --git a/docs/arch/x86_64/interrupt_handling.rst b/docs/arch/x86_64/interrupt_handling.rst deleted file mode 100644 index d4ff94a..0000000 --- a/docs/arch/x86_64/interrupt_handling.rst +++ /dev/null @@ -1,9 +0,0 @@ -Interrupt Handling Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - interrupt_handling/* \ No newline at end of file diff --git a/docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst b/docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst deleted file mode 100644 index 6099170..0000000 --- a/docs/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst +++ /dev/null @@ -1,5 +0,0 @@ -Generic Interrupt Handler -======================= - -.. doxygenfile:: arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp - diff --git a/docs/arch/x86_64/io.rst b/docs/arch/x86_64/io.rst deleted file mode 100644 index 7082bd5..0000000 --- a/docs/arch/x86_64/io.rst +++ /dev/null @@ -1,9 +0,0 @@ -General Input/Output Subsystem -============================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - io/* \ No newline at end of file diff --git a/docs/arch/x86_64/io/port_io.rst b/docs/arch/x86_64/io/port_io.rst deleted file mode 100644 index 18a9f6a..0000000 --- a/docs/arch/x86_64/io/port_io.rst +++ /dev/null @@ -1,6 +0,0 @@ -Port-based Input/Output -======================= - -.. doxygenstruct:: teachos::arch::io::port - :members: - diff --git a/docs/arch/x86_64/kernel.rst b/docs/arch/x86_64/kernel.rst deleted file mode 100644 index 650e3a6..0000000 --- a/docs/arch/x86_64/kernel.rst +++ /dev/null @@ -1,9 +0,0 @@ -Kernel Main Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - kernel/* \ No newline at end of file diff --git a/docs/arch/x86_64/kernel/cpu.rst b/docs/arch/x86_64/kernel/cpu.rst deleted file mode 100644 index da3dfc0..0000000 --- a/docs/arch/x86_64/kernel/cpu.rst +++ /dev/null @@ -1,9 +0,0 @@ -Kernel CPU Registers -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - cpu/* diff --git a/docs/arch/x86_64/kernel/cpu/call.rst b/docs/arch/x86_64/kernel/cpu/call.rst deleted file mode 100644 index 33d15ec..0000000 --- a/docs/arch/x86_64/kernel/cpu/call.rst +++ /dev/null @@ -1,5 +0,0 @@ -Far Call -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/call.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/control_register.rst b/docs/arch/x86_64/kernel/cpu/control_register.rst deleted file mode 100644 index a45c6d9..0000000 --- a/docs/arch/x86_64/kernel/cpu/control_register.rst +++ /dev/null @@ -1,5 +0,0 @@ -Control Register -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/control_register.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/gdtr.rst b/docs/arch/x86_64/kernel/cpu/gdtr.rst deleted file mode 100644 index 41c0f6b..0000000 --- a/docs/arch/x86_64/kernel/cpu/gdtr.rst +++ /dev/null @@ -1,5 +0,0 @@ -Global Descriptor Table Register -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/gdtr.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/idtr.rst b/docs/arch/x86_64/kernel/cpu/idtr.rst deleted file mode 100644 index b4c4bb0..0000000 --- a/docs/arch/x86_64/kernel/cpu/idtr.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Descriptor Table Register -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/idtr.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/if.rst b/docs/arch/x86_64/kernel/cpu/if.rst deleted file mode 100644 index 2dd07b4..0000000 --- a/docs/arch/x86_64/kernel/cpu/if.rst +++ /dev/null @@ -1,5 +0,0 @@ -Interrupt Flag -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/if.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/msr.rst b/docs/arch/x86_64/kernel/cpu/msr.rst deleted file mode 100644 index 75c4f47..0000000 --- a/docs/arch/x86_64/kernel/cpu/msr.rst +++ /dev/null @@ -1,5 +0,0 @@ -Model Specific Register -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/msr.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/segment_register.rst b/docs/arch/x86_64/kernel/cpu/segment_register.rst deleted file mode 100644 index 8159369..0000000 --- a/docs/arch/x86_64/kernel/cpu/segment_register.rst +++ /dev/null @@ -1,5 +0,0 @@ -CPU Segment Register -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/segment_register.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/tlb.rst b/docs/arch/x86_64/kernel/cpu/tlb.rst deleted file mode 100644 index 1ceec1d..0000000 --- a/docs/arch/x86_64/kernel/cpu/tlb.rst +++ /dev/null @@ -1,5 +0,0 @@ -Translation Lookaside Buffer -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/tlb.hpp - diff --git a/docs/arch/x86_64/kernel/cpu/tr.rst b/docs/arch/x86_64/kernel/cpu/tr.rst deleted file mode 100644 index a2b234b..0000000 --- a/docs/arch/x86_64/kernel/cpu/tr.rst +++ /dev/null @@ -1,5 +0,0 @@ -Task Register -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/tr.hpp - diff --git a/docs/arch/x86_64/kernel/halt.rst b/docs/arch/x86_64/kernel/halt.rst deleted file mode 100644 index c425e81..0000000 --- a/docs/arch/x86_64/kernel/halt.rst +++ /dev/null @@ -1,5 +0,0 @@ -Kernel Halt -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/halt.hpp - diff --git a/docs/arch/x86_64/kernel/main.rst b/docs/arch/x86_64/kernel/main.rst deleted file mode 100644 index 194bd85..0000000 --- a/docs/arch/x86_64/kernel/main.rst +++ /dev/null @@ -1,5 +0,0 @@ -Kernel Main -======================= - -.. doxygenfile:: arch/x86_64/include/arch/kernel/main.hpp - diff --git a/docs/arch/x86_64/memory.rst b/docs/arch/x86_64/memory.rst deleted file mode 100644 index 58d12e9..0000000 --- a/docs/arch/x86_64/memory.rst +++ /dev/null @@ -1,9 +0,0 @@ -Kernel Memory Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - memory/* \ No newline at end of file diff --git a/docs/arch/x86_64/memory/allocator.rst b/docs/arch/x86_64/memory/allocator.rst deleted file mode 100644 index 6ce0a74..0000000 --- a/docs/arch/x86_64/memory/allocator.rst +++ /dev/null @@ -1,9 +0,0 @@ -Physical Frame Allocator Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - allocator/* diff --git a/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst b/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst deleted file mode 100644 index 422f33c..0000000 --- a/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Area Physical Frame Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp - diff --git a/docs/arch/x86_64/memory/allocator/concept.rst b/docs/arch/x86_64/memory/allocator/concept.rst deleted file mode 100644 index 734a2ce..0000000 --- a/docs/arch/x86_64/memory/allocator/concept.rst +++ /dev/null @@ -1,5 +0,0 @@ -Physical Frame Allocator Concept -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/concept.hpp - diff --git a/docs/arch/x86_64/memory/allocator/physical_frame.rst b/docs/arch/x86_64/memory/allocator/physical_frame.rst deleted file mode 100644 index c5d0fd2..0000000 --- a/docs/arch/x86_64/memory/allocator/physical_frame.rst +++ /dev/null @@ -1,5 +0,0 @@ -Physical Frame -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/physical_frame.hpp - diff --git a/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst b/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst deleted file mode 100644 index 27401b2..0000000 --- a/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Tiny Physical Frame Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp - diff --git a/docs/arch/x86_64/memory/cpu.rst b/docs/arch/x86_64/memory/cpu.rst deleted file mode 100644 index 4cb5af0..0000000 --- a/docs/arch/x86_64/memory/cpu.rst +++ /dev/null @@ -1,9 +0,0 @@ -CPU Registers Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - cpu/* diff --git a/docs/arch/x86_64/memory/heap.rst b/docs/arch/x86_64/memory/heap.rst deleted file mode 100644 index 409d93a..0000000 --- a/docs/arch/x86_64/memory/heap.rst +++ /dev/null @@ -1,9 +0,0 @@ -Heap Memory Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - heap/* diff --git a/docs/arch/x86_64/memory/heap/bump_allocator.rst b/docs/arch/x86_64/memory/heap/bump_allocator.rst deleted file mode 100644 index b20916e..0000000 --- a/docs/arch/x86_64/memory/heap/bump_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Kernel Heap Bump Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/heap/bump_allocator.hpp - diff --git a/docs/arch/x86_64/memory/heap/global_heap_allocator.rst b/docs/arch/x86_64/memory/heap/global_heap_allocator.rst deleted file mode 100644 index 60ec0b5..0000000 --- a/docs/arch/x86_64/memory/heap/global_heap_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Global Heap Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp - diff --git a/docs/arch/x86_64/memory/heap/heap_allocator.rst b/docs/arch/x86_64/memory/heap/heap_allocator.rst deleted file mode 100644 index b410e41..0000000 --- a/docs/arch/x86_64/memory/heap/heap_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Kernel Heap Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/heap/heap_allocator.hpp - diff --git a/docs/arch/x86_64/memory/heap/linked_list_allocator.rst b/docs/arch/x86_64/memory/heap/linked_list_allocator.rst deleted file mode 100644 index d156852..0000000 --- a/docs/arch/x86_64/memory/heap/linked_list_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Kernel Heap Linked List Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp - diff --git a/docs/arch/x86_64/memory/heap/memory_block.rst b/docs/arch/x86_64/memory/heap/memory_block.rst deleted file mode 100644 index 8ed6566..0000000 --- a/docs/arch/x86_64/memory/heap/memory_block.rst +++ /dev/null @@ -1,5 +0,0 @@ -Heap Linked List Free Memory Block -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/heap/memory_block.hpp - diff --git a/docs/arch/x86_64/memory/heap/user_heap_allocator.rst b/docs/arch/x86_64/memory/heap/user_heap_allocator.rst deleted file mode 100644 index d0febb6..0000000 --- a/docs/arch/x86_64/memory/heap/user_heap_allocator.rst +++ /dev/null @@ -1,5 +0,0 @@ -User Heap Linked List Allocator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp - diff --git a/docs/arch/x86_64/memory/main.rst b/docs/arch/x86_64/memory/main.rst deleted file mode 100644 index d9a9f39..0000000 --- a/docs/arch/x86_64/memory/main.rst +++ /dev/null @@ -1,5 +0,0 @@ -Memory Main -=========== - -.. doxygenfile:: arch/x86_64/include/arch/memory/main.hpp - diff --git a/docs/arch/x86_64/memory/multiboot.rst b/docs/arch/x86_64/memory/multiboot.rst deleted file mode 100644 index 22ec3f2..0000000 --- a/docs/arch/x86_64/memory/multiboot.rst +++ /dev/null @@ -1,9 +0,0 @@ -Kernel Multiboot Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - multiboot/* diff --git a/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst b/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst deleted file mode 100644 index bbd6dfb..0000000 --- a/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst +++ /dev/null @@ -1,5 +0,0 @@ -Multiboot ELF Header Symbols Section Structure -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp - diff --git a/docs/arch/x86_64/memory/multiboot/info.rst b/docs/arch/x86_64/memory/multiboot/info.rst deleted file mode 100644 index 847870d..0000000 --- a/docs/arch/x86_64/memory/multiboot/info.rst +++ /dev/null @@ -1,5 +0,0 @@ -Multiboot Header Information Structure -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/info.hpp - diff --git a/docs/arch/x86_64/memory/multiboot/memory_map.rst b/docs/arch/x86_64/memory/multiboot/memory_map.rst deleted file mode 100644 index 9c77331..0000000 --- a/docs/arch/x86_64/memory/multiboot/memory_map.rst +++ /dev/null @@ -1,5 +0,0 @@ -Multiboot Memory Map Header Structure -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/memory_map.hpp - diff --git a/docs/arch/x86_64/memory/multiboot/reader.rst b/docs/arch/x86_64/memory/multiboot/reader.rst deleted file mode 100644 index fac98e2..0000000 --- a/docs/arch/x86_64/memory/multiboot/reader.rst +++ /dev/null @@ -1,5 +0,0 @@ -Multiboot Reader -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/reader.hpp - diff --git a/docs/arch/x86_64/memory/paging.rst b/docs/arch/x86_64/memory/paging.rst deleted file mode 100644 index 10cd976..0000000 --- a/docs/arch/x86_64/memory/paging.rst +++ /dev/null @@ -1,9 +0,0 @@ -Virtual Page Table Paging Subsystem -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - paging/* diff --git a/docs/arch/x86_64/memory/paging/active_page_table.rst b/docs/arch/x86_64/memory/paging/active_page_table.rst deleted file mode 100644 index 5710131..0000000 --- a/docs/arch/x86_64/memory/paging/active_page_table.rst +++ /dev/null @@ -1,5 +0,0 @@ -Active Page Table -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/active_page_table.hpp - diff --git a/docs/arch/x86_64/memory/paging/inactive_page_table.rst b/docs/arch/x86_64/memory/paging/inactive_page_table.rst deleted file mode 100644 index 5732e64..0000000 --- a/docs/arch/x86_64/memory/paging/inactive_page_table.rst +++ /dev/null @@ -1,5 +0,0 @@ -Inactive Page Table -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp - diff --git a/docs/arch/x86_64/memory/paging/kernel_mapper.rst b/docs/arch/x86_64/memory/paging/kernel_mapper.rst deleted file mode 100644 index 9948e4e..0000000 --- a/docs/arch/x86_64/memory/paging/kernel_mapper.rst +++ /dev/null @@ -1,5 +0,0 @@ -Kernel Mapper -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp - diff --git a/docs/arch/x86_64/memory/paging/page_entry.rst b/docs/arch/x86_64/memory/paging/page_entry.rst deleted file mode 100644 index 8900b0e..0000000 --- a/docs/arch/x86_64/memory/paging/page_entry.rst +++ /dev/null @@ -1,5 +0,0 @@ -Virtual Page Table Entry -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/page_entry.hpp - diff --git a/docs/arch/x86_64/memory/paging/page_table.rst b/docs/arch/x86_64/memory/paging/page_table.rst deleted file mode 100644 index c5ab8c7..0000000 --- a/docs/arch/x86_64/memory/paging/page_table.rst +++ /dev/null @@ -1,5 +0,0 @@ -Virtual Page Table -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/page_table.hpp - diff --git a/docs/arch/x86_64/memory/paging/temporary_page.rst b/docs/arch/x86_64/memory/paging/temporary_page.rst deleted file mode 100644 index 0c63899..0000000 --- a/docs/arch/x86_64/memory/paging/temporary_page.rst +++ /dev/null @@ -1,5 +0,0 @@ -Temporary Virtual Page Table -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/temporary_page.hpp - diff --git a/docs/arch/x86_64/memory/paging/virtual_page.rst b/docs/arch/x86_64/memory/paging/virtual_page.rst deleted file mode 100644 index dd42f47..0000000 --- a/docs/arch/x86_64/memory/paging/virtual_page.rst +++ /dev/null @@ -1,5 +0,0 @@ -Virtual Page -======================= - -.. doxygenfile:: arch/x86_64/include/arch/memory/paging/virtual_page.hpp - diff --git a/docs/arch/x86_64/stl.rst b/docs/arch/x86_64/stl.rst deleted file mode 100644 index bb21f9a..0000000 --- a/docs/arch/x86_64/stl.rst +++ /dev/null @@ -1,9 +0,0 @@ -Standard Library Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - stl/* \ No newline at end of file diff --git a/docs/arch/x86_64/stl/container.rst b/docs/arch/x86_64/stl/container.rst deleted file mode 100644 index 19c735b..0000000 --- a/docs/arch/x86_64/stl/container.rst +++ /dev/null @@ -1,5 +0,0 @@ -Container Structure -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/container.hpp - diff --git a/docs/arch/x86_64/stl/contiguous_pointer_iterator.rst b/docs/arch/x86_64/stl/contiguous_pointer_iterator.rst deleted file mode 100644 index 47f88c4..0000000 --- a/docs/arch/x86_64/stl/contiguous_pointer_iterator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Contiguous Pointer Iterator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp - diff --git a/docs/arch/x86_64/stl/forward_value_iterator.rst b/docs/arch/x86_64/stl/forward_value_iterator.rst deleted file mode 100644 index 72270de..0000000 --- a/docs/arch/x86_64/stl/forward_value_iterator.rst +++ /dev/null @@ -1,5 +0,0 @@ -Forward Value Iterator -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/forward_value_iterator.hpp - diff --git a/docs/arch/x86_64/stl/mutex.rst b/docs/arch/x86_64/stl/mutex.rst deleted file mode 100644 index 2098113..0000000 --- a/docs/arch/x86_64/stl/mutex.rst +++ /dev/null @@ -1,5 +0,0 @@ -Mutex -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/mutex.hpp - diff --git a/docs/arch/x86_64/stl/shared_pointer.rst b/docs/arch/x86_64/stl/shared_pointer.rst deleted file mode 100644 index 46ddb65..0000000 --- a/docs/arch/x86_64/stl/shared_pointer.rst +++ /dev/null @@ -1,5 +0,0 @@ -Shared Pointer -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/shared_pointer.hpp - diff --git a/docs/arch/x86_64/stl/stack.rst b/docs/arch/x86_64/stl/stack.rst deleted file mode 100644 index a554387..0000000 --- a/docs/arch/x86_64/stl/stack.rst +++ /dev/null @@ -1,5 +0,0 @@ -Stack -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/stack.hpp - diff --git a/docs/arch/x86_64/stl/unique_pointer.rst b/docs/arch/x86_64/stl/unique_pointer.rst deleted file mode 100644 index f508763..0000000 --- a/docs/arch/x86_64/stl/unique_pointer.rst +++ /dev/null @@ -1,5 +0,0 @@ -Unique Pointer -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/unique_pointer.hpp - diff --git a/docs/arch/x86_64/stl/vector.rst b/docs/arch/x86_64/stl/vector.rst deleted file mode 100644 index b60023a..0000000 --- a/docs/arch/x86_64/stl/vector.rst +++ /dev/null @@ -1,5 +0,0 @@ -Vector -======================= - -.. doxygenfile:: arch/x86_64/include/arch/stl/vector.hpp - diff --git a/docs/arch/x86_64/user.rst b/docs/arch/x86_64/user.rst deleted file mode 100644 index 3be32bb..0000000 --- a/docs/arch/x86_64/user.rst +++ /dev/null @@ -1,9 +0,0 @@ -User Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - user/* \ No newline at end of file diff --git a/docs/arch/x86_64/user/main.rst b/docs/arch/x86_64/user/main.rst deleted file mode 100644 index 0f641b2..0000000 --- a/docs/arch/x86_64/user/main.rst +++ /dev/null @@ -1,5 +0,0 @@ -User Main -=========== - -.. doxygenfile:: arch/x86_64/include/arch/user/main.hpp - diff --git a/docs/arch/x86_64/video.rst b/docs/arch/x86_64/video.rst deleted file mode 100644 index bbae5ed..0000000 --- a/docs/arch/x86_64/video.rst +++ /dev/null @@ -1,9 +0,0 @@ -Video Output Subsystem -====================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - video/* \ No newline at end of file diff --git a/docs/arch/x86_64/video/vga.rst b/docs/arch/x86_64/video/vga.rst deleted file mode 100644 index 2c32bb2..0000000 --- a/docs/arch/x86_64/video/vga.rst +++ /dev/null @@ -1,9 +0,0 @@ -VGA Support -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - vga/* diff --git a/docs/arch/x86_64/video/vga/io.rst b/docs/arch/x86_64/video/vga/io.rst deleted file mode 100644 index 39609c9..0000000 --- a/docs/arch/x86_64/video/vga/io.rst +++ /dev/null @@ -1,4 +0,0 @@ -VGA Input/Output Types and Constants -==================================== - -.. doxygenfile:: arch/x86_64/include/arch/video/vga/io.hpp diff --git a/docs/arch/x86_64/video/vga/text.rst b/docs/arch/x86_64/video/vga/text.rst deleted file mode 100644 index 592cdd5..0000000 --- a/docs/arch/x86_64/video/vga/text.rst +++ /dev/null @@ -1,5 +0,0 @@ -VGA Text Mode -============= - -.. doxygennamespace:: teachos::arch::video::vga::text - :members: diff --git a/docs/conf.py b/docs/conf.py index 067c1cf..b8cfe69 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,7 +16,7 @@ author = "Felix Morgner" #extensions = ["breathe"] templates_path = ["_templates"] -exclude_patterns = [] +exclude_patterns = ["pre/**"] # -- Options Breathe --------------------------------------------------------- # https://breathe.readthedocs.io/en/stable/directives.html#config-values diff --git a/docs/cross/memory.rst b/docs/cross/memory.rst deleted file mode 100644 index 3a2c1c4..0000000 --- a/docs/cross/memory.rst +++ /dev/null @@ -1,11 +0,0 @@ -Memory Access and Management -============================ - -This sections details the platform-**independent** infrastructure for memory access and management. - -.. toctree:: - :maxdepth: 1 - :glob: - :caption: Types: - - memory/* diff --git a/docs/cross/memory/asm_pointer.rst b/docs/cross/memory/asm_pointer.rst deleted file mode 100644 index 70f5c01..0000000 --- a/docs/cross/memory/asm_pointer.rst +++ /dev/null @@ -1,10 +0,0 @@ -Access to Pointers Defined in Assembly -====================================== - -.. doxygenstruct:: teachos::memory::asm_pointer - :members: - -Specializations ---------------- - -.. doxygenstruct:: teachos::memory::asm_pointer< Type const > \ No newline at end of file diff --git a/docs/pre/arch/x86_64.rst b/docs/pre/arch/x86_64.rst new file mode 100644 index 0000000..dc432f1 --- /dev/null +++ b/docs/pre/arch/x86_64.rst @@ -0,0 +1,9 @@ +x86_64 +====== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + x86_64/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/boot.rst b/docs/pre/arch/x86_64/boot.rst new file mode 100644 index 0000000..8be2a57 --- /dev/null +++ b/docs/pre/arch/x86_64/boot.rst @@ -0,0 +1,9 @@ +Boot Information Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + boot/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/boot/pointers.rst b/docs/pre/arch/x86_64/boot/pointers.rst new file mode 100644 index 0000000..3ec626a --- /dev/null +++ b/docs/pre/arch/x86_64/boot/pointers.rst @@ -0,0 +1,5 @@ +Boot Information Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/boot/pointers.hpp + diff --git a/docs/pre/arch/x86_64/context_switching.rst b/docs/pre/arch/x86_64/context_switching.rst new file mode 100644 index 0000000..c3b3b03 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching.rst @@ -0,0 +1,9 @@ +Context Switching Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + context_switching/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst new file mode 100644 index 0000000..dd6e478 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table.rst @@ -0,0 +1,9 @@ +Interrupt Descriptor Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + interrupt_descriptor_table/* diff --git a/docs/pre/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 new file mode 100644 index 0000000..29e7586 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/gate_descriptor.rst @@ -0,0 +1,5 @@ +Interrupt Gate Descriptor +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..60e8c37 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/idt_flags.rst @@ -0,0 +1,5 @@ +Interrupt Descriptor Flags +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..a2b8997 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table copy.rst @@ -0,0 +1,5 @@ +Interrupt Descriptor Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..3a8c259 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer copy.rst @@ -0,0 +1,5 @@ +Interrupt Descriptor Table Pointer +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..ddba6ee --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/ist_offset.rst @@ -0,0 +1,5 @@ +Interrupt Stack Table Offset +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..2da142e --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/interrupt_descriptor_table/segment_selector.rst @@ -0,0 +1,5 @@ +Segment Selector +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp + diff --git a/docs/pre/arch/x86_64/context_switching/main.rst b/docs/pre/arch/x86_64/context_switching/main.rst new file mode 100644 index 0000000..e9e8a35 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/main.rst @@ -0,0 +1,5 @@ +Context Switching Main +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/main.hpp + diff --git a/docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst new file mode 100644 index 0000000..449622d --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table.rst @@ -0,0 +1,9 @@ +Segment Descriptor Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + segment_descriptor_table/* diff --git a/docs/pre/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 new file mode 100644 index 0000000..f2e7d67 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/access_byte.rst @@ -0,0 +1,5 @@ +Access Byte +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..faa2ffc --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/gdt_flags.rst @@ -0,0 +1,5 @@ +Global Descriptor Table Flags +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..35403db --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table.rst @@ -0,0 +1,5 @@ +Global Descriptor Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..41ceffd --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/global_descriptor_table_pointer.rst @@ -0,0 +1,5 @@ +Global Descriptor Table Pointer +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..952ab2a --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_base.rst @@ -0,0 +1,5 @@ +Segment Descriptor Base (32-bit) +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..874d1cb --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_extension.rst @@ -0,0 +1,5 @@ +Segment Descriptor Extension (64-bit) +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..e45b0a5 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/segment_descriptor_type.rst @@ -0,0 +1,5 @@ +Segment Descriptor Type +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp + diff --git a/docs/pre/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 new file mode 100644 index 0000000..731d7bb --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/segment_descriptor_table/task_state_segment.rst @@ -0,0 +1,5 @@ +Task State Segment +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp + diff --git a/docs/pre/arch/x86_64/context_switching/syscall.rst b/docs/pre/arch/x86_64/context_switching/syscall.rst new file mode 100644 index 0000000..28acf28 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/syscall.rst @@ -0,0 +1,9 @@ +System Call Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + syscall/* diff --git a/docs/pre/arch/x86_64/context_switching/syscall/main.rst b/docs/pre/arch/x86_64/context_switching/syscall/main.rst new file mode 100644 index 0000000..6be577b --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/syscall/main.rst @@ -0,0 +1,5 @@ +System Call Main +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/syscall/main.hpp + diff --git a/docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst b/docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst new file mode 100644 index 0000000..e9162f1 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/syscall/syscall_enable.rst @@ -0,0 +1,5 @@ +System Call Configuration +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp + diff --git a/docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst b/docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst new file mode 100644 index 0000000..0e86780 --- /dev/null +++ b/docs/pre/arch/x86_64/context_switching/syscall/syscall_handler.rst @@ -0,0 +1,5 @@ +System Call Handler +======================= + +.. doxygenfile:: arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp + diff --git a/docs/pre/arch/x86_64/exception_handling.rst b/docs/pre/arch/x86_64/exception_handling.rst new file mode 100644 index 0000000..3bf2770 --- /dev/null +++ b/docs/pre/arch/x86_64/exception_handling.rst @@ -0,0 +1,9 @@ +Exception Handling Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + exception_handling/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/exception_handling/assert.rst b/docs/pre/arch/x86_64/exception_handling/assert.rst new file mode 100644 index 0000000..053cf66 --- /dev/null +++ b/docs/pre/arch/x86_64/exception_handling/assert.rst @@ -0,0 +1,5 @@ +Exception Handling Assertion +======================= + +.. doxygenfile:: arch/x86_64/include/arch/exception_handling/assert.hpp + diff --git a/docs/pre/arch/x86_64/exception_handling/panic.rst b/docs/pre/arch/x86_64/exception_handling/panic.rst new file mode 100644 index 0000000..50b6284 --- /dev/null +++ b/docs/pre/arch/x86_64/exception_handling/panic.rst @@ -0,0 +1,5 @@ +Exception Handling Panic +======================= + +.. doxygenfile:: arch/x86_64/include/arch/exception_handling/panic.hpp + diff --git a/docs/pre/arch/x86_64/interrupt_handling.rst b/docs/pre/arch/x86_64/interrupt_handling.rst new file mode 100644 index 0000000..d4ff94a --- /dev/null +++ b/docs/pre/arch/x86_64/interrupt_handling.rst @@ -0,0 +1,9 @@ +Interrupt Handling Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + interrupt_handling/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst b/docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst new file mode 100644 index 0000000..6099170 --- /dev/null +++ b/docs/pre/arch/x86_64/interrupt_handling/generic_interrupt_handler.rst @@ -0,0 +1,5 @@ +Generic Interrupt Handler +======================= + +.. doxygenfile:: arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp + diff --git a/docs/pre/arch/x86_64/io.rst b/docs/pre/arch/x86_64/io.rst new file mode 100644 index 0000000..7082bd5 --- /dev/null +++ b/docs/pre/arch/x86_64/io.rst @@ -0,0 +1,9 @@ +General Input/Output Subsystem +============================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + io/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/io/port_io.rst b/docs/pre/arch/x86_64/io/port_io.rst new file mode 100644 index 0000000..18a9f6a --- /dev/null +++ b/docs/pre/arch/x86_64/io/port_io.rst @@ -0,0 +1,6 @@ +Port-based Input/Output +======================= + +.. doxygenstruct:: teachos::arch::io::port + :members: + diff --git a/docs/pre/arch/x86_64/kernel.rst b/docs/pre/arch/x86_64/kernel.rst new file mode 100644 index 0000000..650e3a6 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel.rst @@ -0,0 +1,9 @@ +Kernel Main Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + kernel/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/kernel/cpu.rst b/docs/pre/arch/x86_64/kernel/cpu.rst new file mode 100644 index 0000000..da3dfc0 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu.rst @@ -0,0 +1,9 @@ +Kernel CPU Registers +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + cpu/* diff --git a/docs/pre/arch/x86_64/kernel/cpu/call.rst b/docs/pre/arch/x86_64/kernel/cpu/call.rst new file mode 100644 index 0000000..33d15ec --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/call.rst @@ -0,0 +1,5 @@ +Far Call +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/call.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/control_register.rst b/docs/pre/arch/x86_64/kernel/cpu/control_register.rst new file mode 100644 index 0000000..a45c6d9 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/control_register.rst @@ -0,0 +1,5 @@ +Control Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/control_register.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/gdtr.rst b/docs/pre/arch/x86_64/kernel/cpu/gdtr.rst new file mode 100644 index 0000000..41c0f6b --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/gdtr.rst @@ -0,0 +1,5 @@ +Global Descriptor Table Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/gdtr.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/idtr.rst b/docs/pre/arch/x86_64/kernel/cpu/idtr.rst new file mode 100644 index 0000000..b4c4bb0 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/idtr.rst @@ -0,0 +1,5 @@ +Interrupt Descriptor Table Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/idtr.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/if.rst b/docs/pre/arch/x86_64/kernel/cpu/if.rst new file mode 100644 index 0000000..2dd07b4 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/if.rst @@ -0,0 +1,5 @@ +Interrupt Flag +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/if.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/msr.rst b/docs/pre/arch/x86_64/kernel/cpu/msr.rst new file mode 100644 index 0000000..75c4f47 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/msr.rst @@ -0,0 +1,5 @@ +Model Specific Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/msr.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/segment_register.rst b/docs/pre/arch/x86_64/kernel/cpu/segment_register.rst new file mode 100644 index 0000000..8159369 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/segment_register.rst @@ -0,0 +1,5 @@ +CPU Segment Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/segment_register.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/tlb.rst b/docs/pre/arch/x86_64/kernel/cpu/tlb.rst new file mode 100644 index 0000000..1ceec1d --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/tlb.rst @@ -0,0 +1,5 @@ +Translation Lookaside Buffer +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/tlb.hpp + diff --git a/docs/pre/arch/x86_64/kernel/cpu/tr.rst b/docs/pre/arch/x86_64/kernel/cpu/tr.rst new file mode 100644 index 0000000..a2b234b --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/cpu/tr.rst @@ -0,0 +1,5 @@ +Task Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/cpu/tr.hpp + diff --git a/docs/pre/arch/x86_64/kernel/halt.rst b/docs/pre/arch/x86_64/kernel/halt.rst new file mode 100644 index 0000000..c425e81 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/halt.rst @@ -0,0 +1,5 @@ +Kernel Halt +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/halt.hpp + diff --git a/docs/pre/arch/x86_64/kernel/main.rst b/docs/pre/arch/x86_64/kernel/main.rst new file mode 100644 index 0000000..194bd85 --- /dev/null +++ b/docs/pre/arch/x86_64/kernel/main.rst @@ -0,0 +1,5 @@ +Kernel Main +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/main.hpp + diff --git a/docs/pre/arch/x86_64/memory.rst b/docs/pre/arch/x86_64/memory.rst new file mode 100644 index 0000000..58d12e9 --- /dev/null +++ b/docs/pre/arch/x86_64/memory.rst @@ -0,0 +1,9 @@ +Kernel Memory Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + memory/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/memory/allocator.rst b/docs/pre/arch/x86_64/memory/allocator.rst new file mode 100644 index 0000000..6ce0a74 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/allocator.rst @@ -0,0 +1,9 @@ +Physical Frame Allocator Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + allocator/* diff --git a/docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst b/docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst new file mode 100644 index 0000000..422f33c --- /dev/null +++ b/docs/pre/arch/x86_64/memory/allocator/area_frame_allocator.rst @@ -0,0 +1,5 @@ +Area Physical Frame Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/allocator/concept.rst b/docs/pre/arch/x86_64/memory/allocator/concept.rst new file mode 100644 index 0000000..734a2ce --- /dev/null +++ b/docs/pre/arch/x86_64/memory/allocator/concept.rst @@ -0,0 +1,5 @@ +Physical Frame Allocator Concept +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/concept.hpp + diff --git a/docs/pre/arch/x86_64/memory/allocator/physical_frame.rst b/docs/pre/arch/x86_64/memory/allocator/physical_frame.rst new file mode 100644 index 0000000..c5d0fd2 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/allocator/physical_frame.rst @@ -0,0 +1,5 @@ +Physical Frame +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/physical_frame.hpp + diff --git a/docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst b/docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst new file mode 100644 index 0000000..27401b2 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/allocator/tiny_frame_allocator.rst @@ -0,0 +1,5 @@ +Tiny Physical Frame Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/cpu.rst b/docs/pre/arch/x86_64/memory/cpu.rst new file mode 100644 index 0000000..4cb5af0 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/cpu.rst @@ -0,0 +1,9 @@ +CPU Registers Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + cpu/* diff --git a/docs/pre/arch/x86_64/memory/heap.rst b/docs/pre/arch/x86_64/memory/heap.rst new file mode 100644 index 0000000..409d93a --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap.rst @@ -0,0 +1,9 @@ +Heap Memory Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + heap/* diff --git a/docs/pre/arch/x86_64/memory/heap/bump_allocator.rst b/docs/pre/arch/x86_64/memory/heap/bump_allocator.rst new file mode 100644 index 0000000..b20916e --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap/bump_allocator.rst @@ -0,0 +1,5 @@ +Kernel Heap Bump Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/bump_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst b/docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst new file mode 100644 index 0000000..60ec0b5 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap/global_heap_allocator.rst @@ -0,0 +1,5 @@ +Global Heap Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/heap/heap_allocator.rst b/docs/pre/arch/x86_64/memory/heap/heap_allocator.rst new file mode 100644 index 0000000..b410e41 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap/heap_allocator.rst @@ -0,0 +1,5 @@ +Kernel Heap Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/heap_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst b/docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst new file mode 100644 index 0000000..d156852 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap/linked_list_allocator.rst @@ -0,0 +1,5 @@ +Kernel Heap Linked List Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/heap/memory_block.rst b/docs/pre/arch/x86_64/memory/heap/memory_block.rst new file mode 100644 index 0000000..8ed6566 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap/memory_block.rst @@ -0,0 +1,5 @@ +Heap Linked List Free Memory Block +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/memory_block.hpp + diff --git a/docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst b/docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst new file mode 100644 index 0000000..d0febb6 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/heap/user_heap_allocator.rst @@ -0,0 +1,5 @@ +User Heap Linked List Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp + diff --git a/docs/pre/arch/x86_64/memory/main.rst b/docs/pre/arch/x86_64/memory/main.rst new file mode 100644 index 0000000..d9a9f39 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/main.rst @@ -0,0 +1,5 @@ +Memory Main +=========== + +.. doxygenfile:: arch/x86_64/include/arch/memory/main.hpp + diff --git a/docs/pre/arch/x86_64/memory/multiboot.rst b/docs/pre/arch/x86_64/memory/multiboot.rst new file mode 100644 index 0000000..22ec3f2 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/multiboot.rst @@ -0,0 +1,9 @@ +Kernel Multiboot Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + multiboot/* diff --git a/docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst b/docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst new file mode 100644 index 0000000..bbd6dfb --- /dev/null +++ b/docs/pre/arch/x86_64/memory/multiboot/elf_symbols_section.rst @@ -0,0 +1,5 @@ +Multiboot ELF Header Symbols Section Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp + diff --git a/docs/pre/arch/x86_64/memory/multiboot/info.rst b/docs/pre/arch/x86_64/memory/multiboot/info.rst new file mode 100644 index 0000000..847870d --- /dev/null +++ b/docs/pre/arch/x86_64/memory/multiboot/info.rst @@ -0,0 +1,5 @@ +Multiboot Header Information Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/info.hpp + diff --git a/docs/pre/arch/x86_64/memory/multiboot/memory_map.rst b/docs/pre/arch/x86_64/memory/multiboot/memory_map.rst new file mode 100644 index 0000000..9c77331 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/multiboot/memory_map.rst @@ -0,0 +1,5 @@ +Multiboot Memory Map Header Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/memory_map.hpp + diff --git a/docs/pre/arch/x86_64/memory/multiboot/reader.rst b/docs/pre/arch/x86_64/memory/multiboot/reader.rst new file mode 100644 index 0000000..fac98e2 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/multiboot/reader.rst @@ -0,0 +1,5 @@ +Multiboot Reader +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/reader.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging.rst b/docs/pre/arch/x86_64/memory/paging.rst new file mode 100644 index 0000000..10cd976 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging.rst @@ -0,0 +1,9 @@ +Virtual Page Table Paging Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + paging/* diff --git a/docs/pre/arch/x86_64/memory/paging/active_page_table.rst b/docs/pre/arch/x86_64/memory/paging/active_page_table.rst new file mode 100644 index 0000000..5710131 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/active_page_table.rst @@ -0,0 +1,5 @@ +Active Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/active_page_table.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst b/docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst new file mode 100644 index 0000000..5732e64 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/inactive_page_table.rst @@ -0,0 +1,5 @@ +Inactive Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst b/docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst new file mode 100644 index 0000000..9948e4e --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/kernel_mapper.rst @@ -0,0 +1,5 @@ +Kernel Mapper +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging/page_entry.rst b/docs/pre/arch/x86_64/memory/paging/page_entry.rst new file mode 100644 index 0000000..8900b0e --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/page_entry.rst @@ -0,0 +1,5 @@ +Virtual Page Table Entry +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/page_entry.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging/page_table.rst b/docs/pre/arch/x86_64/memory/paging/page_table.rst new file mode 100644 index 0000000..c5ab8c7 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/page_table.rst @@ -0,0 +1,5 @@ +Virtual Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/page_table.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging/temporary_page.rst b/docs/pre/arch/x86_64/memory/paging/temporary_page.rst new file mode 100644 index 0000000..0c63899 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/temporary_page.rst @@ -0,0 +1,5 @@ +Temporary Virtual Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/temporary_page.hpp + diff --git a/docs/pre/arch/x86_64/memory/paging/virtual_page.rst b/docs/pre/arch/x86_64/memory/paging/virtual_page.rst new file mode 100644 index 0000000..dd42f47 --- /dev/null +++ b/docs/pre/arch/x86_64/memory/paging/virtual_page.rst @@ -0,0 +1,5 @@ +Virtual Page +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/virtual_page.hpp + diff --git a/docs/pre/arch/x86_64/stl.rst b/docs/pre/arch/x86_64/stl.rst new file mode 100644 index 0000000..bb21f9a --- /dev/null +++ b/docs/pre/arch/x86_64/stl.rst @@ -0,0 +1,9 @@ +Standard Library Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + stl/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/stl/container.rst b/docs/pre/arch/x86_64/stl/container.rst new file mode 100644 index 0000000..19c735b --- /dev/null +++ b/docs/pre/arch/x86_64/stl/container.rst @@ -0,0 +1,5 @@ +Container Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/container.hpp + diff --git a/docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst b/docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst new file mode 100644 index 0000000..47f88c4 --- /dev/null +++ b/docs/pre/arch/x86_64/stl/contiguous_pointer_iterator.rst @@ -0,0 +1,5 @@ +Contiguous Pointer Iterator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp + diff --git a/docs/pre/arch/x86_64/stl/forward_value_iterator.rst b/docs/pre/arch/x86_64/stl/forward_value_iterator.rst new file mode 100644 index 0000000..72270de --- /dev/null +++ b/docs/pre/arch/x86_64/stl/forward_value_iterator.rst @@ -0,0 +1,5 @@ +Forward Value Iterator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/forward_value_iterator.hpp + diff --git a/docs/pre/arch/x86_64/stl/mutex.rst b/docs/pre/arch/x86_64/stl/mutex.rst new file mode 100644 index 0000000..2098113 --- /dev/null +++ b/docs/pre/arch/x86_64/stl/mutex.rst @@ -0,0 +1,5 @@ +Mutex +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/mutex.hpp + diff --git a/docs/pre/arch/x86_64/stl/shared_pointer.rst b/docs/pre/arch/x86_64/stl/shared_pointer.rst new file mode 100644 index 0000000..46ddb65 --- /dev/null +++ b/docs/pre/arch/x86_64/stl/shared_pointer.rst @@ -0,0 +1,5 @@ +Shared Pointer +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/shared_pointer.hpp + diff --git a/docs/pre/arch/x86_64/stl/stack.rst b/docs/pre/arch/x86_64/stl/stack.rst new file mode 100644 index 0000000..a554387 --- /dev/null +++ b/docs/pre/arch/x86_64/stl/stack.rst @@ -0,0 +1,5 @@ +Stack +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/stack.hpp + diff --git a/docs/pre/arch/x86_64/stl/unique_pointer.rst b/docs/pre/arch/x86_64/stl/unique_pointer.rst new file mode 100644 index 0000000..f508763 --- /dev/null +++ b/docs/pre/arch/x86_64/stl/unique_pointer.rst @@ -0,0 +1,5 @@ +Unique Pointer +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/unique_pointer.hpp + diff --git a/docs/pre/arch/x86_64/stl/vector.rst b/docs/pre/arch/x86_64/stl/vector.rst new file mode 100644 index 0000000..b60023a --- /dev/null +++ b/docs/pre/arch/x86_64/stl/vector.rst @@ -0,0 +1,5 @@ +Vector +======================= + +.. doxygenfile:: arch/x86_64/include/arch/stl/vector.hpp + diff --git a/docs/pre/arch/x86_64/user.rst b/docs/pre/arch/x86_64/user.rst new file mode 100644 index 0000000..3be32bb --- /dev/null +++ b/docs/pre/arch/x86_64/user.rst @@ -0,0 +1,9 @@ +User Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + user/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/user/main.rst b/docs/pre/arch/x86_64/user/main.rst new file mode 100644 index 0000000..0f641b2 --- /dev/null +++ b/docs/pre/arch/x86_64/user/main.rst @@ -0,0 +1,5 @@ +User Main +=========== + +.. doxygenfile:: arch/x86_64/include/arch/user/main.hpp + diff --git a/docs/pre/arch/x86_64/video.rst b/docs/pre/arch/x86_64/video.rst new file mode 100644 index 0000000..bbae5ed --- /dev/null +++ b/docs/pre/arch/x86_64/video.rst @@ -0,0 +1,9 @@ +Video Output Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + video/* \ No newline at end of file diff --git a/docs/pre/arch/x86_64/video/vga.rst b/docs/pre/arch/x86_64/video/vga.rst new file mode 100644 index 0000000..2c32bb2 --- /dev/null +++ b/docs/pre/arch/x86_64/video/vga.rst @@ -0,0 +1,9 @@ +VGA Support +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + vga/* diff --git a/docs/pre/arch/x86_64/video/vga/io.rst b/docs/pre/arch/x86_64/video/vga/io.rst new file mode 100644 index 0000000..39609c9 --- /dev/null +++ b/docs/pre/arch/x86_64/video/vga/io.rst @@ -0,0 +1,4 @@ +VGA Input/Output Types and Constants +==================================== + +.. doxygenfile:: arch/x86_64/include/arch/video/vga/io.hpp diff --git a/docs/pre/arch/x86_64/video/vga/text.rst b/docs/pre/arch/x86_64/video/vga/text.rst new file mode 100644 index 0000000..592cdd5 --- /dev/null +++ b/docs/pre/arch/x86_64/video/vga/text.rst @@ -0,0 +1,5 @@ +VGA Text Mode +============= + +.. doxygennamespace:: teachos::arch::video::vga::text + :members: diff --git a/docs/pre/cross/memory.rst b/docs/pre/cross/memory.rst new file mode 100644 index 0000000..3a2c1c4 --- /dev/null +++ b/docs/pre/cross/memory.rst @@ -0,0 +1,11 @@ +Memory Access and Management +============================ + +This sections details the platform-**independent** infrastructure for memory access and management. + +.. toctree:: + :maxdepth: 1 + :glob: + :caption: Types: + + memory/* diff --git a/docs/pre/cross/memory/asm_pointer.rst b/docs/pre/cross/memory/asm_pointer.rst new file mode 100644 index 0000000..70f5c01 --- /dev/null +++ b/docs/pre/cross/memory/asm_pointer.rst @@ -0,0 +1,10 @@ +Access to Pointers Defined in Assembly +====================================== + +.. doxygenstruct:: teachos::memory::asm_pointer + :members: + +Specializations +--------------- + +.. doxygenstruct:: teachos::memory::asm_pointer< Type const > \ No newline at end of file -- cgit v1.2.3 From dd04850c27e8bc273506f4a64bb28b7ddf111dc5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 20:51:55 +0000 Subject: kapi: rework text device interface --- arch/x86_64/CMakeLists.txt | 2 +- arch/x86_64/include/x86_64/vga/text.hpp | 122 +++++++++++++------------------- arch/x86_64/kapi/cio.cpp | 16 +++++ arch/x86_64/kapi/io.cpp | 36 ---------- arch/x86_64/src/vga/text.cpp | 23 +++--- kapi/CMakeLists.txt | 3 +- kapi/include/kapi/cio.hpp | 29 ++++++++ kapi/include/kapi/io.hpp | 17 ----- kapi/src/cio.cpp | 29 ++++++++ kapi/src/system.cpp | 10 +-- src/main.cpp | 6 +- 11 files changed, 148 insertions(+), 145 deletions(-) create mode 100644 arch/x86_64/kapi/cio.cpp delete mode 100644 arch/x86_64/kapi/io.cpp create mode 100644 kapi/include/kapi/cio.hpp delete mode 100644 kapi/include/kapi/io.hpp create mode 100644 kapi/src/cio.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index c585cbf..e8b5162 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -12,7 +12,7 @@ target_link_libraries("x86_64" PUBLIC target_sources("x86_64" PRIVATE # api::kapi implementation - "kapi/io.cpp" + "kapi/cio.cpp" "kapi/memory.cpp" "kapi/system.cpp" diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index 267eae9..f8e6f1b 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -1,9 +1,10 @@ #ifndef TEACHOS_X86_64_VIDEO_VGA_TEXT_HPP #define TEACHOS_X86_64_VIDEO_VGA_TEXT_HPP +#include "kapi/cio.hpp" + #include #include -#include namespace teachos::x86_64::vga::text { @@ -89,84 +90,57 @@ namespace teachos::x86_64::vga::text 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; + struct device final : teachos::cio::output_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 Move the cursor to a new line, scrolling the buffer if necessary. - */ - auto newline() -> 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 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(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); } - /** - * @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; + private: + /** + * @brief Move the cursor to a new line, scrolling the buffer if necessary. + */ + auto newline() -> void; - template - concept Integral = std::is_integral_v; + /** + * @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 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 - 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; - } - } + /** + * @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; + }; } // namespace teachos::x86_64::vga::text diff --git a/arch/x86_64/kapi/cio.cpp b/arch/x86_64/kapi/cio.cpp new file mode 100644 index 0000000..ac3ae39 --- /dev/null +++ b/arch/x86_64/kapi/cio.cpp @@ -0,0 +1,16 @@ +#include "kapi/cio.hpp" + +#include "x86_64/vga/text.hpp" + +namespace teachos::cio +{ + + auto static constinit vga_device = std::optional{}; + + auto init() -> void + { + vga_device.emplace(); + set_output_device(*vga_device); + } + +} // namespace teachos::cio diff --git a/arch/x86_64/kapi/io.cpp b/arch/x86_64/kapi/io.cpp deleted file mode 100644 index eab6473..0000000 --- a/arch/x86_64/kapi/io.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "kapi/io.hpp" - -#include "x86_64/vga/text.hpp" - -namespace teachos::io -{ - - auto init() -> void - { - x86_64::vga::text::clear(); - x86_64::vga::text::cursor(false); - } - - auto print(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - } - - auto println(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - x86_64::vga::text::newline(); - } - - auto print_error(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - } - - auto println_error(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - x86_64::vga::text::newline(); - } - -} // namespace teachos::io diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 5c94b84..af089fd 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -13,19 +13,24 @@ namespace teachos::x86_64::vga::text { namespace { - auto buffer_offset = std::ptrdiff_t{}; + auto constinit buffer_offset = std::ptrdiff_t{}; auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + + auto write_char(char code_point, attribute attribute) -> void + { + vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; + }; } // namespace - auto clear(attribute attribute) -> void + auto device::clear(attribute attribute) -> void { buffer_offset = 0; std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', std::bit_cast(attribute)}); } - auto cursor(bool enabled) -> void + auto device::cursor(bool enabled) -> void { auto cursor_disable_byte = std::byte{!enabled} << 5; @@ -33,7 +38,7 @@ namespace teachos::x86_64::vga::text crtc::data::write(crtc::data::read() | cursor_disable_byte); } - auto newline() -> void + auto device::newline() -> void { auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; @@ -51,13 +56,15 @@ namespace teachos::x86_64::vga::text } } - auto write_char(char code_point, attribute attribute) -> void + auto device::write(std::string_view code_points, attribute attribute) -> void { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; - }; + std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + } - auto write(std::string_view code_points, attribute attribute) -> void + auto device::writeln(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + newline(); } + } // namespace teachos::x86_64::vga::text diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index 3a15fee..14244bc 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -5,12 +5,13 @@ target_sources("kapi" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES - "include/kapi/io.hpp" + "include/kapi/cio.hpp" "include/kapi/memory.hpp" "include/kapi/system.hpp" ) target_sources("kapi" PRIVATE + "src/cio.cpp" "src/system.cpp" ) diff --git a/kapi/include/kapi/cio.hpp b/kapi/include/kapi/cio.hpp new file mode 100644 index 0000000..6b93638 --- /dev/null +++ b/kapi/include/kapi/cio.hpp @@ -0,0 +1,29 @@ +#ifndef TEACHOS_KAPI_IO_HPP +#define TEACHOS_KAPI_IO_HPP + +#include +#include + +namespace teachos::cio +{ + struct output_device + { + auto virtual write(std::string_view text [[maybe_unused]]) -> void {} + auto virtual writeln(std::string_view text [[maybe_unused]]) -> void {} + + auto virtual write_error(std::string_view text [[maybe_unused]]) -> void {} + auto virtual writeln_error(std::string_view text [[maybe_unused]]) -> void {} + }; + + auto init() -> void; + + auto set_output_device(output_device & device) -> std::optional; + + auto print(std::string_view text) -> void; + auto println(std::string_view text) -> void; + + auto print_error(std::string_view text) -> void; + auto println_error(std::string_view text) -> void; +} // namespace teachos::cio + +#endif diff --git a/kapi/include/kapi/io.hpp b/kapi/include/kapi/io.hpp deleted file mode 100644 index 764738f..0000000 --- a/kapi/include/kapi/io.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef TEACHOS_KAPI_IO_HPP -#define TEACHOS_KAPI_IO_HPP - -#include - -namespace teachos::io -{ - auto init() -> void; - - auto print(std::string_view text) -> void; - auto println(std::string_view text) -> void; - - auto print_error(std::string_view text) -> void; - auto println_error(std::string_view text) -> void; -} // namespace teachos::io - -#endif diff --git a/kapi/src/cio.cpp b/kapi/src/cio.cpp new file mode 100644 index 0000000..aa26d49 --- /dev/null +++ b/kapi/src/cio.cpp @@ -0,0 +1,29 @@ +#include "kapi/cio.hpp" + +#include +#include + +namespace teachos::cio +{ + auto constinit null_device = output_device{}; + + auto constinit active_device = &null_device; + + auto set_output_device(output_device & device) -> std::optional + { + 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/kapi/src/system.cpp b/kapi/src/system.cpp index c3b1c5e..041404e 100644 --- a/kapi/src/system.cpp +++ b/kapi/src/system.cpp @@ -1,16 +1,16 @@ #include "kapi/system.hpp" -#include "kapi/io.hpp" +#include "kapi/cio.hpp" namespace teachos::system { auto panic(std::string_view message, std::source_location location) -> void { - io::println_error("!!!Kernel Panic!!! "); - io::println_error(message); - io::println_error(location.file_name()); - io::println_error(location.function_name()); + cio::println_error("!!!Kernel Panic!!! "); + cio::println_error(message); + cio::println_error(location.file_name()); + cio::println_error(location.function_name()); halt(); } diff --git a/src/main.cpp b/src/main.cpp index d6199d0..120e7e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,11 @@ -#include "kapi/io.hpp" +#include "kapi/cio.hpp" #include "kapi/memory.hpp" #include "kapi/system.hpp" auto main() -> int { - teachos::io::init(); - teachos::io::println("[OS] IO subsystem initialized."); + teachos::cio::init(); + teachos::cio::println("[OS] IO subsystem initialized."); teachos::memory::init(); -- cgit v1.2.3 From 90c3190543b2ac8a7de03ba297f329ee5cc1f513 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 24 Oct 2025 12:14:09 +0000 Subject: ide: switch development container --- .devcontainer/x86-64/devcontainer.json | 39 ++++++++++++++++++++-------------- .gitignore | 14 +++++++----- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index 6b76902..f619e3f 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-4", - "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.1.0-5", + "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,xorriso" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "basdp.language-gas-x86", + "llvm-vs-code-extensions.vscode-clangd", + "ms-vscode.cmake-tools", + "webfreak.debug", + "zixuanwang.linkerscript" + ] + } + }, + "remoteUser": "ubuntu", + "updateRemoteUserUID": true +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 13fb722..d575651 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ -/.venv +.venv/ +.cache/ + +.gdb_history + +.devpod-internal/ + /build -/.conan/install /docs/_build -/.cache -/.gdb_history -/qemu-stderr-*.log + +qemu-*-*.log -- cgit v1.2.3 From ff35119463c30fb23e16c626fea3962e35e4f111 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 27 Oct 2025 13:34:41 +0100 Subject: ide: update toolchain --- .devcontainer/x86-64/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index f619e3f..26c05d0 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -1,6 +1,6 @@ { "name": "TeachOS on x86-64", - "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.1.0-5", + "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.2.0-1", "features": { "ghcr.io/devcontainers/features/git:1": {}, "ghcr.io/devcontainers/features/git-lfs:1": {}, @@ -21,4 +21,4 @@ }, "remoteUser": "ubuntu", "updateRemoteUserUID": true -} \ No newline at end of file +} -- cgit v1.2.3 From 13bedf43d619abb100beb91db6e1b072e07e3d74 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 27 Oct 2025 13:12:07 +0000 Subject: ide: reconfigure debugging extension --- .devcontainer/x86-64/devcontainer.json | 2 +- .vscode/extensions.json | 6 +++++- .vscode/launch.json | 31 +++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index 26c05d0..4c6afab 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -14,7 +14,7 @@ "basdp.language-gas-x86", "llvm-vs-code-extensions.vscode-clangd", "ms-vscode.cmake-tools", - "webfreak.debug", + "KylinIdeTeam.cppdebug", "zixuanwang.linkerscript" ] } 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 6739aa3..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.sym", - "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" + } ] } ] -- cgit v1.2.3 From 2977db0fc27ca30fa4f734751e11fce9625caabc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 27 Oct 2025 14:15:27 +0100 Subject: ide: add ssh to devcontainer --- .devcontainer/x86-64/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index 4c6afab..38a7695 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -5,7 +5,7 @@ "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,xorriso" + "packages": "cmake,grub2-common,grub-pc,mtools,ninja-build,qemu-system-x86,ssh,xorriso" } }, "customizations": { -- cgit v1.2.3 From 7671b1f0e4790b43bb8f8747b63cd44b7a65e10f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 27 Oct 2025 13:58:55 +0000 Subject: x86_64: move kapi implementation to src --- arch/x86_64/CMakeLists.txt | 10 +++---- arch/x86_64/kapi/cio.cpp | 16 ---------- arch/x86_64/kapi/memory.cpp | 66 ----------------------------------------- arch/x86_64/kapi/system.cpp | 12 -------- arch/x86_64/src/kapi/cio.cpp | 16 ++++++++++ arch/x86_64/src/kapi/memory.cpp | 66 +++++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/kapi/system.cpp | 12 ++++++++ 7 files changed, 99 insertions(+), 99 deletions(-) delete mode 100644 arch/x86_64/kapi/cio.cpp delete mode 100644 arch/x86_64/kapi/memory.cpp delete mode 100644 arch/x86_64/kapi/system.cpp create mode 100644 arch/x86_64/src/kapi/cio.cpp create mode 100644 arch/x86_64/src/kapi/memory.cpp create mode 100644 arch/x86_64/src/kapi/system.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index e8b5162..9be7b04 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -11,11 +11,6 @@ target_link_libraries("x86_64" PUBLIC ) target_sources("x86_64" PRIVATE - # api::kapi implementation - "kapi/cio.cpp" - "kapi/memory.cpp" - "kapi/system.cpp" - # Low-level bootstrap "src/boot/boot32.S" "src/boot/entry64.s" @@ -25,6 +20,11 @@ target_sources("x86_64" PRIVATE # CPU intrinsics "src/cpu/registers.cpp" + # api::kapi implementation + "src/kapi/cio.cpp" + "src/kapi/memory.cpp" + "src/kapi/system.cpp" + # Memory management "src/memory/mmu.cpp" "src/memory/region_allocator.cpp" diff --git a/arch/x86_64/kapi/cio.cpp b/arch/x86_64/kapi/cio.cpp deleted file mode 100644 index ac3ae39..0000000 --- a/arch/x86_64/kapi/cio.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "kapi/cio.hpp" - -#include "x86_64/vga/text.hpp" - -namespace teachos::cio -{ - - auto static constinit vga_device = std::optional{}; - - auto init() -> void - { - vga_device.emplace(); - set_output_device(*vga_device); - } - -} // namespace teachos::cio diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp deleted file mode 100644 index d1c1f03..0000000 --- a/arch/x86_64/kapi/memory.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "kapi/memory.hpp" - -#include "kapi/system.hpp" - -#include "x86_64/boot/boot.hpp" -#include "x86_64/boot/ld.hpp" -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/region_allocator.hpp" - -#include - -#include - -namespace teachos::memory -{ - using namespace x86_64::memory; - using namespace x86_64::boot; - - namespace - { - auto constinit is_initialized = std::atomic_flag{}; - - auto create_memory_information() -> region_allocator::memory_information - { - auto const & mbi = multiboot_information_pointer.get(); - auto map = mbi->memory_map(); - - return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), - std::make_pair(physical_address{std::bit_cast(&mbi)}, - physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), - map}; - }; - } // namespace - - auto init() -> void - { - if (is_initialized.test_and_set()) - { - system::panic("[x86_64] Memory management has already been initialized."); - } - - auto memory_map = multiboot_information_pointer->maybe_memory_map(); - if (!memory_map) - { - system::panic("[x86_64] No memory map available."); - } - - auto mem_info = create_memory_information(); - auto allocator = region_allocator{mem_info}; - - static_cast(allocator); - - // 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::memory diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp deleted file mode 100644 index 2d4c3fe..0000000 --- a/arch/x86_64/kapi/system.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "kapi/system.hpp" - -namespace teachos::system -{ - - auto halt() -> void - { - asm volatile("1: hlt\njmp 1b"); - __builtin_unreachable(); - } - -} // namespace teachos::system diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp new file mode 100644 index 0000000..ac3ae39 --- /dev/null +++ b/arch/x86_64/src/kapi/cio.cpp @@ -0,0 +1,16 @@ +#include "kapi/cio.hpp" + +#include "x86_64/vga/text.hpp" + +namespace teachos::cio +{ + + auto static constinit vga_device = std::optional{}; + + auto init() -> void + { + vga_device.emplace(); + set_output_device(*vga_device); + } + +} // namespace teachos::cio diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp new file mode 100644 index 0000000..d1c1f03 --- /dev/null +++ b/arch/x86_64/src/kapi/memory.cpp @@ -0,0 +1,66 @@ +#include "kapi/memory.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/region_allocator.hpp" + +#include + +#include + +namespace teachos::memory +{ + using namespace x86_64::memory; + using namespace x86_64::boot; + + namespace + { + auto constinit is_initialized = std::atomic_flag{}; + + auto create_memory_information() -> region_allocator::memory_information + { + auto const & mbi = multiboot_information_pointer.get(); + auto map = mbi->memory_map(); + + return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), + std::make_pair(physical_address{std::bit_cast(&mbi)}, + physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + map}; + }; + } // namespace + + auto init() -> void + { + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] Memory management has already been initialized."); + } + + auto memory_map = multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + system::panic("[x86_64] No memory map available."); + } + + auto mem_info = create_memory_information(); + auto allocator = region_allocator{mem_info}; + + static_cast(allocator); + + // 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::memory diff --git a/arch/x86_64/src/kapi/system.cpp b/arch/x86_64/src/kapi/system.cpp new file mode 100644 index 0000000..2d4c3fe --- /dev/null +++ b/arch/x86_64/src/kapi/system.cpp @@ -0,0 +1,12 @@ +#include "kapi/system.hpp" + +namespace teachos::system +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace teachos::system -- cgit v1.2.3 From 36a6401141217812384ed8c63815d702206366cd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 28 Oct 2025 09:38:35 +0100 Subject: ide: fix clangd query driver glob --- .vscode/settings.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0d62c95..91b307a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,22 +1,24 @@ { "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, }, - + "[gas]": { - "editor.rulers": [80] + "editor.rulers": [ + 80 + ] } - } \ No newline at end of file +} \ No newline at end of file -- cgit v1.2.3 From 081edba16a917f5a56dd2c1c39eceb5e20f600b1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 28 Oct 2025 09:42:31 +0100 Subject: build: simplify toolchain setup --- cmake/Platforms/x86_64.cmake | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index f969cb3..afdc0ec 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -14,15 +14,17 @@ find_program(CMAKE_ASM_COMPILER "${CMAKE_ASM_COMPILER_TARGET}-gcc" 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 \ --ffunction-sections \ --fdata-sections" + "-mno-red-zone" + "-mcmodel=kernel" + "-fno-pie" + "-fno-rtti" + "-fno-exceptions" + "-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_DEBUG "-ggdb3") -- cgit v1.2.3 From 9535226376ea812007fbe8a2aaf6cf3ccb77c263 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 28 Oct 2025 17:12:04 +0100 Subject: ide: update toolchain --- .devcontainer/x86-64/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index 38a7695..3599657 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -1,6 +1,6 @@ { "name": "TeachOS on x86-64", - "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:15.2.0-1", + "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": {}, -- cgit v1.2.3 From 12dedc7e2e51390fdf2caec3700e75db19be1cd4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 28 Oct 2025 18:31:39 +0100 Subject: kstd: don't rely on newlib --- CMakeLists.txt | 1 - kapi/CMakeLists.txt | 1 - libs/kstd/CMakeLists.txt | 8 ++++++++ libs/kstd/include/kstd/bits/os.hpp | 2 ++ libs/kstd/src/bits/os.cpp | 10 ++++++++++ libs/kstd/src/cstdlib.cpp | 18 ++++++++++++++++++ libs/kstd/src/cstring.cpp | 10 ++++++++++ src/abort.cpp | 3 --- src/kstd.cpp | 6 ++++++ 9 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 libs/kstd/src/bits/os.cpp create mode 100644 libs/kstd/src/cstdlib.cpp create mode 100644 libs/kstd/src/cstring.cpp delete mode 100644 src/abort.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3251847..ed4b16c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,6 @@ add_subdirectory("kapi") add_subdirectory("libs") add_executable("kernel" - "src/abort.cpp" "src/kstd.cpp" "src/main.cpp" ) diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index 14244bc..86b0fb6 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -22,7 +22,6 @@ target_include_directories("kapi" PUBLIC target_link_libraries("kapi" PUBLIC "libs::kstd" - "c" "gcc" "stdc++" ) diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index ac9e78f..666a5d7 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -2,6 +2,9 @@ add_library("kstd" STATIC) add_library("libs::kstd" ALIAS "kstd") target_sources("kstd" PRIVATE + "src/bits/os.cpp" + "src/cstdlib.cpp" + "src/cstring.cpp" "src/mutex.cpp" ) @@ -23,3 +26,8 @@ target_sources("kstd" PUBLIC target_include_directories("kstd" PUBLIC "include" ) + +target_link_options("kstd" INTERFACE + "-Wl,--undefined=abort" + "-Wl,--undefined=strlen" +) \ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp index 0425b88..7f5fcc8 100644 --- a/libs/kstd/include/kstd/bits/os.hpp +++ b/libs/kstd/include/kstd/bits/os.hpp @@ -6,6 +6,8 @@ namespace kstd::os { + auto abort() -> bool; + [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; } diff --git a/libs/kstd/src/bits/os.cpp b/libs/kstd/src/bits/os.cpp new file mode 100644 index 0000000..fb64202 --- /dev/null +++ b/libs/kstd/src/bits/os.cpp @@ -0,0 +1,10 @@ +#include "kstd/bits/os.hpp" + +namespace kstd::os +{ + [[gnu::weak]] + auto abort() -> bool + { + return false; + } +} // namespace kstd::os \ No newline at end of file diff --git a/libs/kstd/src/cstdlib.cpp b/libs/kstd/src/cstdlib.cpp new file mode 100644 index 0000000..8fb5f63 --- /dev/null +++ b/libs/kstd/src/cstdlib.cpp @@ -0,0 +1,18 @@ +#include "kstd/bits/os.hpp" + +namespace kstd +{ + + extern "C" + { + [[noreturn]] auto abort() -> void + { + if (!kstd::os::abort()) + { + os::panic("System abort handler returned."); + } + __builtin_trap(); + } + } + +} // namespace kstd \ No newline at end of file diff --git a/libs/kstd/src/cstring.cpp b/libs/kstd/src/cstring.cpp new file mode 100644 index 0000000..5419b7d --- /dev/null +++ b/libs/kstd/src/cstring.cpp @@ -0,0 +1,10 @@ +#include +#include + +extern "C" +{ + auto strlen(const char * string) -> std::size_t + { + return std::distance(string, std::ranges::find(string, nullptr, '\0')); + } +} diff --git a/src/abort.cpp b/src/abort.cpp deleted file mode 100644 index 6b0070e..0000000 --- a/src/abort.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "kapi/system.hpp" - -extern "C" [[noreturn]] auto abort() -> void { teachos::system::panic("Abort called"); } diff --git a/src/kstd.cpp b/src/kstd.cpp index 2149c12..77155af 100644 --- a/src/kstd.cpp +++ b/src/kstd.cpp @@ -5,6 +5,12 @@ namespace kstd::os { + auto abort() -> bool + { + panic("Abort called."); + return true; + } + auto panic(std::string_view message, std::source_location location) -> void { teachos::system::panic(message, location); -- cgit v1.2.3 From 27a00c67d0110ddaebb4035e68860e00e32a3b8f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 28 Oct 2025 18:36:55 +0100 Subject: build: upgrade to C++23 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed4b16c..2d45997 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ 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_CXX_STANDARD "20") +set(CMAKE_CXX_STANDARD "23") set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS NO) -- cgit v1.2.3 From acabbacdee68ad80e829bda56ae5363d04646d2d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 10:39:30 +0100 Subject: kstd: clean up libc implementation --- libs/kstd/CMakeLists.txt | 16 ++++++++++------ libs/kstd/include/kstd/bits/os.hpp | 25 ++++++++++++++++++++++--- libs/kstd/src/bits/os.cpp | 6 +++--- libs/kstd/src/cstdlib.cpp | 18 ------------------ libs/kstd/src/cstring.cpp | 10 ---------- libs/kstd/src/libc/stdlib.cpp | 11 +++++++++++ libs/kstd/src/libc/string.cpp | 15 +++++++++++++++ src/kstd.cpp | 6 ------ 8 files changed, 61 insertions(+), 46 deletions(-) delete mode 100644 libs/kstd/src/cstdlib.cpp delete mode 100644 libs/kstd/src/cstring.cpp create mode 100644 libs/kstd/src/libc/stdlib.cpp create mode 100644 libs/kstd/src/libc/string.cpp diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 666a5d7..75c2315 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -1,10 +1,15 @@ add_library("kstd" STATIC) add_library("libs::kstd" ALIAS "kstd") +set(KSTD_LIBC_SYMBOLS + "abort" + "strlen" +) + target_sources("kstd" PRIVATE "src/bits/os.cpp" - "src/cstdlib.cpp" - "src/cstring.cpp" + "src/libc/stdlib.cpp" + "src/libc/string.cpp" "src/mutex.cpp" ) @@ -27,7 +32,6 @@ target_include_directories("kstd" PUBLIC "include" ) -target_link_options("kstd" INTERFACE - "-Wl,--undefined=abort" - "-Wl,--undefined=strlen" -) \ No newline at end of file +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/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp index 7f5fcc8..0474f16 100644 --- a/libs/kstd/include/kstd/bits/os.hpp +++ b/libs/kstd/include/kstd/bits/os.hpp @@ -6,10 +6,29 @@ namespace kstd::os { - auto abort() -> bool; + /** + * @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 = std::source_location::current()) -> void; -} + 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/libs/kstd/src/bits/os.cpp b/libs/kstd/src/bits/os.cpp index fb64202..e6edbfd 100644 --- a/libs/kstd/src/bits/os.cpp +++ b/libs/kstd/src/bits/os.cpp @@ -2,9 +2,9 @@ namespace kstd::os { - [[gnu::weak]] - auto abort() -> bool + [[gnu::weak, noreturn]] + auto abort() -> void { - return false; + os::panic("Abort called."); } } // namespace kstd::os \ No newline at end of file diff --git a/libs/kstd/src/cstdlib.cpp b/libs/kstd/src/cstdlib.cpp deleted file mode 100644 index 8fb5f63..0000000 --- a/libs/kstd/src/cstdlib.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "kstd/bits/os.hpp" - -namespace kstd -{ - - extern "C" - { - [[noreturn]] auto abort() -> void - { - if (!kstd::os::abort()) - { - os::panic("System abort handler returned."); - } - __builtin_trap(); - } - } - -} // namespace kstd \ No newline at end of file diff --git a/libs/kstd/src/cstring.cpp b/libs/kstd/src/cstring.cpp deleted file mode 100644 index 5419b7d..0000000 --- a/libs/kstd/src/cstring.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -extern "C" -{ - auto strlen(const char * string) -> std::size_t - { - return std::distance(string, std::ranges::find(string, nullptr, '\0')); - } -} diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp new file mode 100644 index 0000000..fe1bc95 --- /dev/null +++ b/libs/kstd/src/libc/stdlib.cpp @@ -0,0 +1,11 @@ +#include "kstd/bits/os.hpp" + +namespace kstd::libc +{ + + extern "C" + { + [[noreturn]] auto abort() -> void { kstd::os::abort(); } + } + +} // 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..c6b3847 --- /dev/null +++ b/libs/kstd/src/libc/string.cpp @@ -0,0 +1,15 @@ +#include +#include + +namespace kstd::libc +{ + + extern "C" + { + auto strlen(const char * string) -> std::size_t + { + return std::distance(string, std::ranges::find(string, nullptr, '\0')); + } + } + +} // namespace kstd::libc \ No newline at end of file diff --git a/src/kstd.cpp b/src/kstd.cpp index 77155af..2149c12 100644 --- a/src/kstd.cpp +++ b/src/kstd.cpp @@ -5,12 +5,6 @@ namespace kstd::os { - auto abort() -> bool - { - panic("Abort called."); - return true; - } - auto panic(std::string_view message, std::source_location location) -> void { teachos::system::panic(message, location); -- cgit v1.2.3 From 6434de8ff75a9143847ef529bc209790ac4909b3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:09:42 +0100 Subject: kapi: move frame and address to KAPI --- arch/x86_64/include/x86_64/boot/boot.hpp | 26 +++--- arch/x86_64/include/x86_64/boot/ld.hpp | 4 +- arch/x86_64/include/x86_64/cpu/registers.hpp | 4 +- arch/x86_64/include/x86_64/device_io/port_io.hpp | 4 +- arch/x86_64/include/x86_64/memory/address.hpp | 47 ----------- arch/x86_64/include/x86_64/memory/frame.hpp | 95 ---------------------- arch/x86_64/include/x86_64/memory/mmu.hpp | 6 +- .../include/x86_64/memory/region_allocator.hpp | 8 +- arch/x86_64/include/x86_64/vga/crtc.hpp | 8 +- arch/x86_64/include/x86_64/vga/text.hpp | 4 +- arch/x86_64/src/cpu/registers.cpp | 4 +- arch/x86_64/src/kapi/cio.cpp | 2 +- arch/x86_64/src/kapi/memory.cpp | 8 +- arch/x86_64/src/memory/mmu.cpp | 6 +- arch/x86_64/src/memory/region_allocator.cpp | 16 +--- arch/x86_64/src/vga/text.cpp | 6 +- kapi/include/kapi/memory.hpp | 5 +- kapi/include/kapi/memory/address.hpp | 47 +++++++++++ kapi/include/kapi/memory/frame.hpp | 92 +++++++++++++++++++++ src/main.cpp | 2 +- 20 files changed, 198 insertions(+), 196 deletions(-) delete mode 100644 arch/x86_64/include/x86_64/memory/address.hpp delete mode 100644 arch/x86_64/include/x86_64/memory/frame.hpp create mode 100644 kapi/include/kapi/memory/address.hpp create mode 100644 kapi/include/kapi/memory/frame.hpp diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 1887e73..86f8ce3 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -48,18 +48,22 @@ #include -extern "C" +namespace teachos::boot::x86_64 { - /** - * @brief A pointer to the multiboot 2 information structure provided by the boot loader. - */ - extern kstd::asm_ptr multiboot_information_pointer; - - /** - * @brief A pointer to the VGA text mode buffer. - */ - extern kstd::asm_ptr> vga_buffer_pointer; -} + + extern "C" + { + /** + * @brief A pointer to the multiboot 2 information structure provided by the boot loader. + */ + extern kstd::asm_ptr multiboot_information_pointer; + + /** + * @brief A pointer to the VGA text mode buffer. + */ + extern kstd::asm_ptr> vga_buffer_pointer; + } +} // namespace teachos::boot::x86_64 #endif diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index 51eb23b..cf59c66 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -17,7 +17,7 @@ #include -namespace teachos::x86_64::boot +namespace teachos::boot::x86_64 { /** * @var _start_physical @@ -42,6 +42,6 @@ namespace teachos::x86_64::boot * @see _start_physical */ extern "C" std::byte _end_physical; -} // namespace teachos::x86_64::boot +} // namespace teachos::boot::x86_64 #endif diff --git a/arch/x86_64/include/x86_64/cpu/registers.hpp b/arch/x86_64/include/x86_64/cpu/registers.hpp index 607d559..d19acfc 100644 --- a/arch/x86_64/include/x86_64/cpu/registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -3,7 +3,7 @@ #include -namespace teachos::x86_64::cpu +namespace teachos::cpu::x86_64 { /** @@ -67,6 +67,6 @@ namespace teachos::x86_64::cpu */ auto set_cr0_bit(cr0_flags flag) -> void; -} // namespace teachos::x86_64::cpu +} // 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 index 4cf0b65..352a4d0 100644 --- a/arch/x86_64/include/x86_64/device_io/port_io.hpp +++ b/arch/x86_64/include/x86_64/device_io/port_io.hpp @@ -5,7 +5,7 @@ #include #include -namespace teachos::x86_64::io +namespace teachos::io::x86_64 { /** * @brief An I/O port of a given size at a given address. @@ -127,6 +127,6 @@ namespace teachos::x86_64::io } }; -} // namespace teachos::x86_64::io +} // namespace teachos::io::x86_64 #endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/address.hpp b/arch/x86_64/include/x86_64/memory/address.hpp deleted file mode 100644 index 20e9655..0000000 --- a/arch/x86_64/include/x86_64/memory/address.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_ADDRESS_HPP -#define TEACHOS_X86_64_MEMORY_ADDRESS_HPP - -#include -#include -#include -#include - -namespace teachos::x86_64::memory -{ - - enum struct address_type : bool - { - linear, - physical, - }; - - template - struct address - { - constexpr explicit address(std::uintptr_t value) noexcept - : m_value{value} - { - } - - explicit address(std::byte * pointer) noexcept - : m_value{std::bit_cast(pointer)} - { - } - - explicit operator std::byte *() const noexcept { return std::bit_cast(m_value); } - - auto constexpr operator<=>(address const &) const noexcept -> std::strong_ordering = default; - auto constexpr operator==(address const &) const noexcept -> bool = default; - - auto constexpr raw() const noexcept -> std::uintptr_t { return m_value; } - - private: - std::uintptr_t m_value{}; - }; - - using linear_address = address; - using physical_address = address; - -} // namespace teachos::x86_64::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/frame.hpp b/arch/x86_64/include/x86_64/memory/frame.hpp deleted file mode 100644 index 21565fd..0000000 --- a/arch/x86_64/include/x86_64/memory/frame.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_FRAME_HPP -#define TEACHOS_X86_64_MEMORY_FRAME_HPP - -#include "x86_64/memory/address.hpp" - -#include -#include - -namespace teachos::x86_64::memory -{ - /** - * @brief Specific physical frame containing helper functions to determine if a specific address is in that - * physical frame or not. - */ - struct frame - { - auto static inline constexpr DEFAULT_SIZE = std::size_t{4096}; ///< Default page size of x86_84 is always 4KiB. - - /** - * @brief Defaulted constructor. - */ - constexpr frame() = default; - - /** - * @brief Constructor. - * - * @param frame_number Index number that should be assigned to this physical frame. - */ - explicit constexpr frame(std::size_t number) - : m_number(number) - { - } - - /** - * @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 constexpr static containing(physical_address address) noexcept -> frame - { - return frame{address.raw() / DEFAULT_SIZE}; - } - - /** - * @brief Get the start address of this physical frame. - * - * @return Start address of the physical frame. - */ - auto constexpr start_address() const noexcept -> physical_address - { - return physical_address{m_number * DEFAULT_SIZE}; - } - - auto constexpr operator+(std::size_t offset) const noexcept -> frame { return frame{m_number + offset}; } - - /** - * @brief Post increment operator. Returns a copy of the value. - * - * @return Copy of the incremented underlying frame number. - */ - auto constexpr operator++(int) noexcept -> frame - { - auto copy = *this; - return ++copy; - } - - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying frame number. - */ - auto constexpr operator++() noexcept -> frame & - { - ++m_number; - return *this; - } - - /** - * @brief Defaulted equals operator. - */ - auto constexpr operator==(frame const & other) const noexcept -> bool = default; - - /** - * @brief Defaulted three-way comparison operator. - */ - auto constexpr operator<=>(frame const & other) const noexcept -> std::strong_ordering = default; - - private: - std::size_t m_number{}; ///< Index number of the current physical frame, used to distinguish it from other frames. - }; - -} // namespace teachos::x86_64::memory - -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_frame_HPP diff --git a/arch/x86_64/include/x86_64/memory/mmu.hpp b/arch/x86_64/include/x86_64/memory/mmu.hpp index b03ffa2..323d18a 100644 --- a/arch/x86_64/include/x86_64/memory/mmu.hpp +++ b/arch/x86_64/include/x86_64/memory/mmu.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_MEMORY_MMU_HPP #define TEACHOS_X86_64_MEMORY_MMU_HPP -#include "x86_64/memory/address.hpp" +#include "kapi/memory/address.hpp" -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { /** * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained @@ -22,6 +22,6 @@ namespace teachos::x86_64::memory */ auto tlb_flush_all() -> void; -} // namespace teachos::x86_64::memory +} // 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 index 23bea10..a918195 100644 --- a/arch/x86_64/include/x86_64/memory/region_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -1,15 +1,15 @@ #ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP #define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/frame.hpp" +#include "kapi/memory/address.hpp" +#include "kapi/memory/frame.hpp" #include #include #include -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { /** * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any @@ -71,6 +71,6 @@ namespace teachos::x86_64::memory frame const m_multiboot_end; ///< The end address of the multiboot code in memory. }; -} // namespace teachos::x86_64::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/vga/crtc.hpp b/arch/x86_64/include/x86_64/vga/crtc.hpp index 4b4eac5..e5ab9f1 100644 --- a/arch/x86_64/include/x86_64/vga/crtc.hpp +++ b/arch/x86_64/include/x86_64/vga/crtc.hpp @@ -5,17 +5,17 @@ #include -namespace teachos::x86_64::vga::crtc +namespace teachos::vga::x86_64::crtc { /** * @brief The address port of the CRT Controller. */ - using address = x86_64::io::port<0x3d4, 1>; + using address = io::x86_64::port<0x3d4, 1>; /** * @brief The data port of the CRT Controller. */ - using data = x86_64::io::port<0x3d5, 1>; + using data = io::x86_64::port<0x3d5, 1>; namespace registers { @@ -30,6 +30,6 @@ namespace teachos::x86_64::vga::crtc [[maybe_unused]] auto constexpr cursor_end = std::byte{0x0b}; } // namespace registers -} // namespace teachos::x86_64::vga::crtc +} // 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 index f8e6f1b..c193576 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -6,7 +6,7 @@ #include #include -namespace teachos::x86_64::vga::text +namespace teachos::vga::x86_64::text { /** * @brief The colors available in the standard VGA text mode. @@ -142,6 +142,6 @@ namespace teachos::x86_64::vga::text auto writeln(std::string_view code_points, attribute attribute) -> void; }; -} // namespace teachos::x86_64::vga::text +} // 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/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp index 7ade98d..8646829 100644 --- a/arch/x86_64/src/cpu/registers.cpp +++ b/arch/x86_64/src/cpu/registers.cpp @@ -2,7 +2,7 @@ #include -namespace teachos::x86_64::cpu +namespace teachos::cpu::x86_64 { auto read_control_register(control_register cr) -> uint64_t { @@ -61,4 +61,4 @@ namespace teachos::x86_64::cpu auto const cr0 = read_control_register(control_register::cr0); write_control_register(control_register::cr0, static_cast::type>(flag) | cr0); } -} // namespace teachos::x86_64::cpu +} // namespace teachos::cpu::x86_64 diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp index ac3ae39..eb0142a 100644 --- a/arch/x86_64/src/kapi/cio.cpp +++ b/arch/x86_64/src/kapi/cio.cpp @@ -5,7 +5,7 @@ namespace teachos::cio { - auto static constinit vga_device = std::optional{}; + auto static constinit vga_device = std::optional{}; auto init() -> void { diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index d1c1f03..55e6ba9 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,10 +1,10 @@ #include "kapi/memory.hpp" +#include "kapi/memory/frame.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/memory/address.hpp" #include "x86_64/memory/region_allocator.hpp" #include @@ -13,8 +13,10 @@ namespace teachos::memory { - using namespace x86_64::memory; - using namespace x86_64::boot; + using namespace boot::x86_64; + using namespace memory::x86_64; + + std::size_t const PLATFORM_FRAME_SIZE{4096}; namespace { diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index 31783fe..e573b4e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -2,8 +2,10 @@ #include "x86_64/cpu/registers.hpp" -namespace teachos::x86_64::memory +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"); @@ -14,4 +16,4 @@ namespace teachos::x86_64::memory auto current_value = cpu::read_control_register(cpu::control_register::cr3); cpu::write_control_register(cpu::control_register::cr3, current_value); } -} // namespace teachos::x86_64::memory +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index c9a98b4..91a5d49 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -1,22 +1,14 @@ -// #include "arch/memory/allocator/region_allocator.hpp" - -// #include "arch/exception_handling/assert.hpp" - -// #include -// #include -// #include - #include "x86_64/memory/region_allocator.hpp" -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/frame.hpp" +#include "kapi/memory/address.hpp" +#include "kapi/memory/frame.hpp" #include #include #include -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { namespace { @@ -92,4 +84,4 @@ namespace teachos::x86_64::memory } auto region_allocator::deallocate_frame(frame const &) -> void {} -} // namespace teachos::x86_64::memory +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index af089fd..8f78ea9 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -9,8 +9,10 @@ #include #include -namespace teachos::x86_64::vga::text +namespace teachos::vga::x86_64::text { + using boot::x86_64::vga_buffer_pointer; + namespace { auto constinit buffer_offset = std::ptrdiff_t{}; @@ -67,4 +69,4 @@ namespace teachos::x86_64::vga::text newline(); } -} // namespace teachos::x86_64::vga::text +} // namespace teachos::vga::x86_64::text diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp index 842a2fa..3ad5ac5 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/include/kapi/memory.hpp @@ -1,9 +1,12 @@ #ifndef TEACHOS_KAPI_MEMORY_HPP #define TEACHOS_KAPI_MEMORY_HPP +#include "kapi/memory/address.hpp" // IWYU pragma: export +#include "kapi/memory/frame.hpp" // IWYU pragma: export + namespace teachos::memory { auto init() -> 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..585807a --- /dev/null +++ b/kapi/include/kapi/memory/address.hpp @@ -0,0 +1,47 @@ +#ifndef TEACHOS_KAPI_MEMORY_ADDRESS_HPP +#define TEACHOS_KAPI_MEMORY_ADDRESS_HPP + +#include +#include +#include +#include + +namespace teachos::memory +{ + + enum struct address_type : bool + { + linear, + physical, + }; + + template + struct address + { + constexpr explicit address(std::uintptr_t value) noexcept + : m_value{value} + { + } + + explicit address(std::byte * pointer) noexcept + : m_value{std::bit_cast(pointer)} + { + } + + explicit operator std::byte *() const noexcept { return std::bit_cast(m_value); } + + auto constexpr operator<=>(address const &) const noexcept -> std::strong_ordering = default; + auto constexpr operator==(address const &) const noexcept -> bool = default; + + auto constexpr raw() const noexcept -> std::uintptr_t { return m_value; } + + private: + std::uintptr_t m_value{}; + }; + + using linear_address = address; + using physical_address = address; + +} // 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..1251e51 --- /dev/null +++ b/kapi/include/kapi/memory/frame.hpp @@ -0,0 +1,92 @@ +#ifndef TEACHOS_KAPI_MEMORY_FRAME_HPP +#define TEACHOS_KAPI_MEMORY_FRAME_HPP + +#include "kapi/memory/address.hpp" + +#include +#include +#include +#include + +namespace teachos::memory +{ + + extern std::size_t const PLATFORM_FRAME_SIZE; + + struct frame + { + constexpr frame() = default; + + explicit constexpr frame(std::size_t number) + : m_number{number} + { + } + + /** + * @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 constexpr static containing(physical_address address) noexcept -> frame + { + return frame{address.raw() / PLATFORM_FRAME_SIZE}; + } + + /** + * @brief Get the start address of this physical frame. + * + * @return Start address of the physical frame. + */ + auto constexpr start_address() const noexcept -> physical_address + { + return physical_address{m_number * PLATFORM_FRAME_SIZE}; + } + + /** + * @brief Get the nth next frame. + * + * @param offset + * @return A new frame n frames after this one. + */ + auto constexpr operator+(std::size_t n) const noexcept -> frame { return frame{m_number + n}; } + + /** + * @brief Increment this frame to refer to the next one, returning a copy. + * + * @return Copy of the incremented underlying frame number. + */ + auto constexpr operator++(int) noexcept -> frame + { + auto copy = *this; + return ++copy; + } + + /** + * @brief Increment this frame to refer to the next one, returning a this frame. + * + * @return Reference to the incremented underlying frame number. + */ + auto constexpr operator++() noexcept -> frame & + { + ++m_number; + return *this; + } + + /** + * @brief Check if this frame refers to the same frame as @p other. + */ + auto constexpr operator==(frame const & other) const noexcept -> bool = default; + + /** + * @brief Lexicographically compare this frame to @p other. + */ + auto constexpr operator<=>(frame const & other) const noexcept -> std::strong_ordering = default; + + private: + std::size_t m_number{}; + }; + +} // namespace teachos::memory + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 120e7e0..fc7d2f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,5 +9,5 @@ auto main() -> int teachos::memory::init(); - teachos::system::panic("Architecture specific main returned!"); + teachos::system::panic("Returning from kernel main!"); } -- cgit v1.2.3 From e7b04ef7f5da8e014e8b85fcf65448b317cca8ff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:15:50 +0100 Subject: kapi: move halt to cpu namespace --- arch/x86_64/CMakeLists.txt | 2 +- arch/x86_64/src/kapi/cpu.cpp | 12 ++++++++++++ arch/x86_64/src/kapi/system.cpp | 12 ------------ kapi/include/kapi/cpu.hpp | 13 +++++++++++++ kapi/include/kapi/system.hpp | 2 -- kapi/src/system.cpp | 4 +++- 6 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 arch/x86_64/src/kapi/cpu.cpp delete mode 100644 arch/x86_64/src/kapi/system.cpp create mode 100644 kapi/include/kapi/cpu.hpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9be7b04..a681347 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -22,8 +22,8 @@ target_sources("x86_64" PRIVATE # api::kapi implementation "src/kapi/cio.cpp" + "src/kapi/cpu.cpp" "src/kapi/memory.cpp" - "src/kapi/system.cpp" # Memory management "src/memory/mmu.cpp" 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/system.cpp b/arch/x86_64/src/kapi/system.cpp deleted file mode 100644 index 2d4c3fe..0000000 --- a/arch/x86_64/src/kapi/system.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "kapi/system.hpp" - -namespace teachos::system -{ - - auto halt() -> void - { - asm volatile("1: hlt\njmp 1b"); - __builtin_unreachable(); - } - -} // namespace teachos::system diff --git a/kapi/include/kapi/cpu.hpp b/kapi/include/kapi/cpu.hpp new file mode 100644 index 0000000..673deab --- /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 +{ + /** + * @brief Halt the CPU, effectively terminating kernel execution. + * + */ + [[noreturn]] auto halt() -> void; +} // namespace teachos::cpu + +#endif diff --git a/kapi/include/kapi/system.hpp b/kapi/include/kapi/system.hpp index 0d4f2c9..b0b0e28 100644 --- a/kapi/include/kapi/system.hpp +++ b/kapi/include/kapi/system.hpp @@ -6,8 +6,6 @@ namespace teachos::system { - [[noreturn]] auto halt() -> void; - [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; } // namespace teachos::system diff --git a/kapi/src/system.cpp b/kapi/src/system.cpp index 041404e..3ae3f29 100644 --- a/kapi/src/system.cpp +++ b/kapi/src/system.cpp @@ -1,10 +1,12 @@ #include "kapi/system.hpp" #include "kapi/cio.hpp" +#include "kapi/cpu.hpp" namespace teachos::system { + [[gnu::weak]] auto panic(std::string_view message, std::source_location location) -> void { cio::println_error("!!!Kernel Panic!!! "); @@ -12,7 +14,7 @@ namespace teachos::system cio::println_error(location.file_name()); cio::println_error(location.function_name()); - halt(); + cpu::halt(); } } // namespace teachos::system -- cgit v1.2.3 From 845a96f5e6bfbbbeba19bf3df07f0e9de53d9a88 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:40:49 +0100 Subject: kapi: export frame_allocator interface --- .../x86_64/include/x86_64/memory/region_allocator.hpp | 7 ++++--- arch/x86_64/src/kapi/memory.cpp | 12 ++++++++++++ arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- kapi/include/kapi/memory.hpp | 6 ++++-- kapi/include/kapi/memory/frame_allocator.hpp | 19 +++++++++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 kapi/include/kapi/memory/frame_allocator.hpp diff --git a/arch/x86_64/include/x86_64/memory/region_allocator.hpp b/arch/x86_64/include/x86_64/memory/region_allocator.hpp index a918195..913b0bb 100644 --- a/arch/x86_64/include/x86_64/memory/region_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -3,6 +3,7 @@ #include "kapi/memory/address.hpp" #include "kapi/memory/frame.hpp" +#include "kapi/memory/frame_allocator.hpp" #include @@ -15,7 +16,7 @@ namespace teachos::memory::x86_64 * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any * deallocated frames. */ - struct region_allocator + struct region_allocator final : frame_allocator { struct memory_information { @@ -43,7 +44,7 @@ namespace teachos::memory::x86_64 * * @return next free physical frame or nullopt if none was found. */ - auto allocate_frame() -> std::optional; + auto allocate() -> std::optional override; /** * @brief Deallocates a previously allocated physical frame. @@ -54,7 +55,7 @@ namespace teachos::memory::x86_64 * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(frame const & physical_frame) -> void; + auto release(frame frame) -> void override; private: /** diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 55e6ba9..be47941 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,6 +1,7 @@ #include "kapi/memory.hpp" #include "kapi/memory/frame.hpp" +#include "kapi/memory/frame_allocator.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" @@ -21,6 +22,7 @@ namespace teachos::memory namespace { auto constinit is_initialized = std::atomic_flag{}; + auto constinit allocator = static_cast(nullptr); auto create_memory_information() -> region_allocator::memory_information { @@ -34,6 +36,16 @@ namespace teachos::memory }; } // namespace + auto active_allocator() -> frame_allocator & + { + if (!allocator) + { + system::panic("[x86_64] The frame allocator has not been set yet."); + } + + return *allocator; + } + auto init() -> void { if (is_initialized.test_and_set()) diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 91a5d49..11ffce2 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -51,7 +51,7 @@ namespace teachos::memory::x86_64 } } - auto region_allocator::allocate_frame() -> std::optional + auto region_allocator::allocate() -> std::optional { if (!m_current_region) { @@ -80,8 +80,8 @@ namespace teachos::memory::x86_64 return allocated; } - return allocate_frame(); + return allocate(); } - auto region_allocator::deallocate_frame(frame const &) -> void {} + auto region_allocator::release(frame) -> void {} } // namespace teachos::memory::x86_64 diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp index 3ad5ac5..3daaa86 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/include/kapi/memory.hpp @@ -1,11 +1,13 @@ #ifndef TEACHOS_KAPI_MEMORY_HPP #define TEACHOS_KAPI_MEMORY_HPP -#include "kapi/memory/address.hpp" // IWYU pragma: export -#include "kapi/memory/frame.hpp" // IWYU pragma: export +#include "kapi/memory/address.hpp" // IWYU pragma: export +#include "kapi/memory/frame.hpp" // IWYU pragma: export +#include "kapi/memory/frame_allocator.hpp" // IWYU pragma: export namespace teachos::memory { + auto active_allocator() -> frame_allocator &; auto init() -> void; } // namespace teachos::memory diff --git a/kapi/include/kapi/memory/frame_allocator.hpp b/kapi/include/kapi/memory/frame_allocator.hpp new file mode 100644 index 0000000..f9393ee --- /dev/null +++ b/kapi/include/kapi/memory/frame_allocator.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP +#define TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP + +#include "kapi/memory/frame.hpp" + +#include + +namespace teachos::memory +{ + + struct frame_allocator + { + virtual auto allocate() -> std::optional = 0; + virtual auto release(frame frame) -> void = 0; + }; + +} // namespace teachos::memory + +#endif // TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP \ No newline at end of file -- cgit v1.2.3 From c71d18f32e06fb456bc2829d9dfc5b42b78160b0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:53:34 +0100 Subject: x86_64: reduce using namespace use --- arch/x86_64/src/kapi/memory.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index be47941..46686b6 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -6,6 +6,7 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" +#include "x86_64/cpu/registers.hpp" #include "x86_64/memory/region_allocator.hpp" #include @@ -14,9 +15,6 @@ namespace teachos::memory { - using namespace boot::x86_64; - using namespace memory::x86_64; - std::size_t const PLATFORM_FRAME_SIZE{4096}; namespace @@ -24,12 +22,13 @@ namespace teachos::memory auto constinit is_initialized = std::atomic_flag{}; auto constinit allocator = static_cast(nullptr); - auto create_memory_information() -> region_allocator::memory_information + auto create_memory_information() -> x86_64::region_allocator::memory_information { - auto const & mbi = multiboot_information_pointer.get(); + auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); auto map = mbi->memory_map(); - return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), + return {std::make_pair(physical_address{&boot::x86_64::_start_physical}, + physical_address{&boot::x86_64::_end_physical}), std::make_pair(physical_address{std::bit_cast(&mbi)}, physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), map}; @@ -53,19 +52,20 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto memory_map = multiboot_information_pointer->maybe_memory_map(); + auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); if (!memory_map) { system::panic("[x86_64] No memory map available."); } auto mem_info = create_memory_information(); - auto allocator = region_allocator{mem_info}; + auto allocator = x86_64::region_allocator{mem_info}; static_cast(allocator); - // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); - // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); + cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); + + // set_efer_bit(efer_flags::NXE); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From f5aee1e1ab521d6aeb4c79f6ef276625159e202f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:58:12 +0100 Subject: x86_64: extract early boot steps --- arch/x86_64/src/kapi/memory.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 46686b6..a29a0cd 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -33,6 +33,23 @@ namespace teachos::memory physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), map}; }; + + auto create_early_frame_allocator() + { + auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + system::panic("[x86_64] Failed to create early allocator, no memory map available."); + } + + return x86_64::region_allocator{create_memory_information()}; + } + + auto enable_cpu_protections() -> void + { + cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); + // set_efer_bit(efer_flags::NXE); + } } // namespace auto active_allocator() -> frame_allocator & @@ -52,20 +69,8 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); - if (!memory_map) - { - system::panic("[x86_64] No memory map available."); - } - - auto mem_info = create_memory_information(); - auto allocator = x86_64::region_allocator{mem_info}; - - static_cast(allocator); - - cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); - - // set_efer_bit(efer_flags::NXE); + [[maybe_unused]] auto allocator = create_early_frame_allocator(); + enable_cpu_protections(); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From f06fc25b9a54a800c5301eec7320903380da947c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:11:09 +0100 Subject: x86_64/memory: simplify region allocator --- arch/x86_64/src/memory/region_allocator.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 11ffce2..d94e810 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -16,6 +16,11 @@ namespace teachos::memory::x86_64 { return frame::containing(physical_address{region.base + region.size_in_B - 1}); } + + auto constexpr 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) @@ -65,19 +70,17 @@ namespace teachos::memory::x86_64 { choose_next_area(); } - else if (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + else if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) { m_next_frame = m_kernel_end + 1; } - else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + else if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) { m_next_frame = m_multiboot_end + 1; } else { - auto allocated = m_next_frame; - ++m_next_frame; - return allocated; + return m_next_frame++; } return allocate(); -- cgit v1.2.3 From 40e67a6dba7837c562613016bdc8bad17d069e57 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:24:41 +0100 Subject: x86_64/memory: fix region allocator initialization During construction, the memory map was not extracted from the supplied memory information. This lead to a situation in which the allocator would never allocate any frames since it believed that there was no memory in the system. --- arch/x86_64/src/memory/region_allocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index d94e810..13103c7 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -26,7 +26,7 @@ namespace teachos::memory::x86_64 region_allocator::region_allocator(memory_information const & mem_info) : m_next_frame{} , m_current_region{} - , m_memory_map{} + , 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)) -- cgit v1.2.3 From 3a0b5678af98832e480115c409495ce835642a09 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:26:52 +0100 Subject: kapi/memory: fix frame number postfix increment --- kapi/include/kapi/memory/frame.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp index 1251e51..8bcf79f 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/include/kapi/memory/frame.hpp @@ -59,7 +59,8 @@ namespace teachos::memory auto constexpr operator++(int) noexcept -> frame { auto copy = *this; - return ++copy; + ++*this; + return copy; } /** -- cgit v1.2.3 From 465817e3e124bafb95de0d8a030b66bc067046b6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 13:35:58 +0100 Subject: x86_64/memory: fix region_allocator initialization --- arch/x86_64/src/kapi/memory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index a29a0cd..61d462f 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -29,8 +29,8 @@ namespace teachos::memory return {std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), - std::make_pair(physical_address{std::bit_cast(&mbi)}, - physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + std::make_pair(physical_address{std::bit_cast(mbi)}, + physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), map}; }; -- cgit v1.2.3 From c2b0bdfe3b725166f16c742cdaca7969052df382 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 13:38:35 +0100 Subject: x86_64/boot: add missing linker script symbols --- arch/x86_64/include/x86_64/boot/ld.hpp | 66 ++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index cf59c66..104e6ee 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -19,29 +19,49 @@ namespace teachos::boot::x86_64 { - /** - * @var _start_physical - * @brief The first byte of the loaded kernel image. - * - * @details - * This symbols is defined in the kernel linker script and marks the start of the kernel image in physical memory. - * To use this symbol for its intended purpose, the address of it shall be taken. - * - * @see _end_physical - */ - extern "C" std::byte _start_physical; - - /** - * @var _end_physical - * @brief The first byte after the loaded kernel image. - * - * @details - * This symbols is defined in the kernel linker script and marks the end of the kernel image in physical memory. - * To use this symbol for its intended purpose, the address of it shall be taken. - * - * @see _start_physical - */ - extern "C" std::byte _end_physical; + + extern "C" + { + /** + * @brief The first byte of the loaded kernel image. + * + * @details + * This symbol is defined in the kernel linker script and marks the start of the kernel image in physical memory. + * To use this symbol for its intended purpose, the address of it shall be taken. + * + * @see _end_physical + */ + extern std::byte _start_physical; + + /** + * @brief The first byte after the loaded kernel image. + * + * @details + * This symbol is defined in the kernel linker script and marks the end of the kernel image in physical memory. + * To use this symbol for its intended purpose, the address of it shall be taken. + * + * @see _start_physical + */ + extern std::byte _end_physical; + + /** + * @brief The first byte of the loaded kernel image in the virtual address space. + * + * @details + * This symbol is defined in the kernel linker script and marks the start of the kernel image in virtual memory. + * To use this symbol for its intended purpose, the address of it shall be taken. + */ + extern std::byte _start_virtual; + + /** + * @brief The first byte after the loaded kernel image in the virtual address space. + * + * @details + * This symbol is defined in the kernel linker script and marks the end of the kernel image in virtual memory. + * To use this symbol for its intended purpose, the address of it shall be taken. + */ + extern std::byte _end_virtual; + } } // namespace teachos::boot::x86_64 #endif -- cgit v1.2.3 From b157e2c472d8bd67ac1656404a6a6ee821260f4b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 15:01:43 +0100 Subject: chore: reformat source code --- .clang-format | 158 +++++++++++++-------- arch/x86_64/include/x86_64/boot/boot.hpp | 3 +- arch/x86_64/include/x86_64/vga/crtc.hpp | 4 +- arch/x86_64/include/x86_64/vga/text.hpp | 28 ++-- .../segment_selector.hpp | 6 +- .../arch/context_switching/syscall/main.hpp | 5 +- .../arch/memory/allocator/tiny_frame_allocator.hpp | 2 +- .../arch/memory/heap/global_heap_allocator.hpp | 19 ++- .../include/arch/memory/heap/heap_allocator.hpp | 8 +- .../arch/memory/heap/linked_list_allocator.hpp | 6 +- .../arch/memory/heap/user_heap_allocator.hpp | 6 +- .../pre/include/arch/memory/multiboot/reader.hpp | 2 +- .../arch/memory/paging/active_page_table.hpp | 4 +- .../include/arch/memory/paging/kernel_mapper.hpp | 18 +-- .../pre/include/arch/memory/paging/page_table.hpp | 2 +- .../include/arch/memory/paging/virtual_page.hpp | 4 +- .../interrupt_descriptor_table/idt_flags.cpp | 5 +- .../interrupt_descriptor_table.cpp | 2 +- .../segment_selector.cpp | 15 +- arch/x86_64/pre/src/context_switching/main.cpp | 13 +- .../segment_descriptor_table/access_byte.cpp | 5 +- .../segment_descriptor_table/gdt_flags.cpp | 10 +- .../global_descriptor_table.cpp | 10 +- .../segment_descriptor_base.cpp | 5 +- .../segment_descriptor_extension.cpp | 10 +- .../context_switching/syscall/syscall_enable.cpp | 10 +- .../context_switching/syscall/syscall_handler.cpp | 11 +- arch/x86_64/pre/src/exception_handling/abort.cpp | 5 +- arch/x86_64/pre/src/exception_handling/panic.cpp | 5 +- arch/x86_64/pre/src/kernel/cpu/if.cpp | 10 +- arch/x86_64/pre/src/kernel/cpu/msr.cpp | 2 +- .../src/memory/allocator/area_frame_allocator.cpp | 5 +- .../pre/src/memory/heap/global_heap_allocator.cpp | 33 +++-- arch/x86_64/pre/src/memory/heap/memory_block.cpp | 5 +- .../pre/src/memory/heap/user_heap_allocator.cpp | 4 +- arch/x86_64/pre/src/memory/main.cpp | 4 +- .../src/memory/multiboot/elf_symbols_section.cpp | 5 +- .../pre/src/memory/paging/active_page_table.cpp | 11 +- arch/x86_64/pre/src/memory/paging/page_entry.cpp | 27 +++- arch/x86_64/pre/src/memory/paging/page_table.cpp | 20 ++- arch/x86_64/pre/src/memory/paging/virtual_page.cpp | 7 +- arch/x86_64/src/boot/initialize_runtime.cpp | 4 +- arch/x86_64/src/memory/region_allocator.cpp | 4 +- arch/x86_64/src/vga/text.cpp | 4 +- kapi/include/kapi/memory/address.hpp | 18 ++- kapi/include/kapi/memory/frame.hpp | 20 +-- kapi/src/cio.cpp | 20 ++- libs/kstd/include/kstd/bits/shared_ptr.hpp | 6 +- libs/kstd/include/kstd/bits/unique_ptr.hpp | 6 +- libs/kstd/src/libc/stdlib.cpp | 5 +- libs/kstd/src/libc/string.cpp | 2 +- libs/kstd/src/mutex.cpp | 10 +- libs/multiboot2/include/multiboot2/constants.hpp | 2 +- libs/multiboot2/include/multiboot2/impl/data.hpp | 7 +- .../include/multiboot2/impl/iterator.hpp | 19 ++- libs/multiboot2/include/multiboot2/impl/tag.hpp | 34 ++--- libs/multiboot2/include/multiboot2/information.hpp | 102 ++++++++++--- 57 files changed, 518 insertions(+), 259 deletions(-) diff --git a/.clang-format b/.clang-format index 714f716..6d3fa9d 100644 --- a/.clang-format +++ b/.clang-format @@ -1,80 +1,116 @@ --- -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: - # Kernel API Headers - - Regex: 'kapi/[[:alnum:]._\/]+\.hpp' + - Regex: kapi/[[:alnum:]._\/]+\.hpp Priority: 100 - # Architecture Implementation Headers - - Regex: 'x86_64/[[:alnum:]._\/]+\.hpp' + - Regex: x86_64/[[:alnum:]._\/]+\.hpp Priority: 110 - # Library Headers - - Regex: '[[:alnum:]._\/]+\.hpp' + - Regex: "[[:alnum:]._\\/]+\\.hpp" Priority: 300 - # STL Headers - - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' + - Regex: <[[:alnum:]._]+(?!\.(h|hpp))> Priority: 900 -IndentCaseLabels: 'true' +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/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 86f8ce3..3a3620d 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -2,6 +2,7 @@ #define TEACHOS_X86_64_BOOT_BOOT_H #ifdef __ASSEMBLER__ +/* clang-format off */ /** * @brief The number of huge pages to map during bootstrap. */ @@ -41,7 +42,7 @@ * @brief The "L" bit in a GDT entry. */ #define GDT_LONG_MODE (1 << 53) - +/* clang-format on */ #else #include diff --git a/arch/x86_64/include/x86_64/vga/crtc.hpp b/arch/x86_64/include/x86_64/vga/crtc.hpp index e5ab9f1..be72ac4 100644 --- a/arch/x86_64/include/x86_64/vga/crtc.hpp +++ b/arch/x86_64/include/x86_64/vga/crtc.hpp @@ -22,12 +22,12 @@ namespace teachos::vga::x86_64::crtc /** * @brief The address of the Cursor Start register of the CRTC. */ - [[maybe_unused]] auto constexpr cursor_start = std::byte{0x0a}; + [[maybe_unused]] constexpr auto cursor_start = std::byte{0x0a}; /** * @brief The address of the Cursor End register of the CRTC. */ - [[maybe_unused]] auto constexpr cursor_end = std::byte{0x0b}; + [[maybe_unused]] constexpr auto cursor_end = std::byte{0x0b}; } // namespace registers } // namespace teachos::vga::x86_64::crtc diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index c193576..858350f 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -68,25 +68,25 @@ namespace teachos::vga::x86_64::text /** * @brief Make the affected cell display with a gray foreground and black background. */ - [[maybe_unused]] auto constexpr gray_on_black = + [[maybe_unused]] constexpr auto 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 = + [[maybe_unused]] constexpr auto green_on_black = attribute{color::green, 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 red_on_black = + [[maybe_unused]] constexpr auto red_on_black = attribute{color::red, 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 = + [[maybe_unused]] constexpr auto white_on_red = attribute{color::gray, foreground_flag::intense, color::red, background_flag::none}; } // namespace common_attributes @@ -108,10 +108,22 @@ namespace teachos::vga::x86_64::text */ 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); } + 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: /** diff --git a/arch/x86_64/pre/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/pre/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/pre/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/pre/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/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp index 1ceb74d..1e4746d 100644 --- a/arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/pre/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::allocator { namespace { - uint8_t constexpr TINY_ALLOCATOR_FRAMES_COUNT = 3U; + constexpr uint8_t TINY_ALLOCATOR_FRAMES_COUNT = 3U; } /** diff --git a/arch/x86_64/pre/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/pre/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/pre/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/pre/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/pre/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp index bbbad19..540ff5c 100644 --- a/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp @@ -3,7 +3,6 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/heap/memory_block.hpp" - #include namespace teachos::arch::memory::heap @@ -44,7 +43,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. diff --git a/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp index 3b47f15..15d8574 100644 --- a/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp +++ b/arch/x86_64/pre/include/arch/memory/heap/user_heap_allocator.hpp @@ -5,6 +5,7 @@ // #include #include + #include namespace teachos::arch::memory::heap @@ -47,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. diff --git a/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp index c5464cb..ba80918 100644 --- a/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp @@ -5,9 +5,9 @@ // #include "arch/memory/multiboot/memory_map.hpp" #include "arch/memory/multiboot/elf_symbols_section.hpp" +#include #include -#include #include namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp index f68d8b6..abefd61 100644 --- a/arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/pre/include/arch/memory/paging/active_page_table.hpp @@ -25,7 +25,7 @@ namespace teachos::arch::memory::paging * * @return Active single unique instance of the level 4 page table. */ - static auto create_or_get() -> active_page_table &; + auto static create_or_get() -> active_page_table &; /** * @brief Index operator overload to access specific mutable entry directy of the level 4 page table. @@ -186,7 +186,7 @@ namespace teachos::arch::memory::paging * @param handle Page Table handle we want to access the entry that should be cleared on. */ template - static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + auto static 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]; diff --git a/arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp index 3afb54b..581f142 100644 --- a/arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/pre/include/arch/memory/paging/kernel_mapper.hpp @@ -47,7 +47,7 @@ namespace teachos::arch::memory::paging 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}; + temporary_page temporary_page{virtual_page{0xCAFE'BABE}, allocator}; decltype(auto) active_table = active_page_table::create_or_get(); auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), @@ -124,14 +124,14 @@ namespace teachos::arch::memory::paging 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 constexpr USER_SECTION_BASES = { - 0x102000, // .boot_bss (Contains statically allocated variables) - 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) - 0x217000, // .user_text (Contains the actual user code executed) - 0x21E000, // .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) + constexpr std::array USER_SECTION_BASES = { + 0x102000, // .boot_bss (Contains statically allocated variables) + 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) + 0x217000, // .user_text (Contains the actual user code executed) + 0x21E000, // .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) diff --git a/arch/x86_64/pre/include/arch/memory/paging/page_table.hpp b/arch/x86_64/pre/include/arch/memory/paging/page_table.hpp index b972337..247086c 100644 --- a/arch/x86_64/pre/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/pre/include/arch/memory/paging/page_table.hpp @@ -7,7 +7,7 @@ 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. + constexpr std::size_t 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. diff --git a/arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp index a6c8c39..1a20eae 100644 --- a/arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/pre/include/arch/memory/paging/virtual_page.hpp @@ -73,12 +73,12 @@ namespace teachos::arch::memory::paging /** * @brief Defaulted equals operator. */ - auto operator==(const virtual_page & other) const -> bool = default; + auto operator==(virtual_page const & other) const -> bool = default; /** * @brief Defaulted three-way comparsion operator. */ - auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; + auto operator<=>(virtual_page const & 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. diff --git a/arch/x86_64/pre/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/pre/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/pre/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/pre/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/pre/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/pre/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(this); } + segment_selector::operator uint16_t() const + { + return *reinterpret_cast(this); + } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/main.cpp b/arch/x86_64/pre/src/context_switching/main.cpp index 9539428..3eb6dae 100644 --- a/arch/x86_64/pre/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/pre/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/pre/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/pre/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/pre/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/pre/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/pre/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/pre/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/pre/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(this); } + segment_descriptor_base::operator uint64_t() const + { + return *reinterpret_cast(this); + } } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/pre/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/pre/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/pre/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/pre/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/pre/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/pre/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(buffer), + video::vga::text::write(reinterpret_cast(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(arg_1)); + teachos::arch::exception_handling::assert(arg_0, reinterpret_cast(arg_1)); break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); diff --git a/arch/x86_64/pre/src/exception_handling/abort.cpp b/arch/x86_64/pre/src/exception_handling/abort.cpp index e12e4cb..5dc6869 100644 --- a/arch/x86_64/pre/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/pre/src/exception_handling/panic.cpp b/arch/x86_64/pre/src/exception_handling/panic.cpp index 8e3802a..9511a9a 100644 --- a/arch/x86_64/pre/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/pre/src/kernel/cpu/if.cpp b/arch/x86_64/pre/src/kernel/cpu/if.cpp index 60a90a3..5d056fc 100644 --- a/arch/x86_64/pre/src/kernel/cpu/if.cpp +++ b/arch/x86_64/pre/src/kernel/cpu/if.cpp @@ -1,7 +1,13 @@ namespace teachos::arch::kernel::cpu { - auto set_interrupt_flag() -> void { asm volatile("sti"); } + auto set_interrupt_flag() -> void + { + asm volatile("sti"); + } - auto clear_interrupt_flag() -> void { asm volatile("cli"); } + auto clear_interrupt_flag() -> void + { + asm volatile("cli"); + } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/msr.cpp b/arch/x86_64/pre/src/kernel/cpu/msr.cpp index 9c474a1..9d6a318 100644 --- a/arch/x86_64/pre/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/pre/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp index a5a1b49..3105023 100644 --- a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp @@ -81,5 +81,8 @@ namespace teachos::arch::memory::allocator return allocate_frame(); } - auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { (void)physical_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/pre/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/pre/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/pre/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/pre/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(this), 0U, sizeof(memory_block)); } + memory_block::~memory_block() + { + memset(static_cast(this), 0U, sizeof(memory_block)); + } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/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/pre/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(&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/pre/src/memory/main.cpp b/arch/x86_64/pre/src/memory/main.cpp index 2746a71..b5980db 100644 --- a/arch/x86_64/pre/src/memory/main.cpp +++ b/arch/x86_64/pre/src/memory/main.cpp @@ -15,7 +15,7 @@ namespace teachos::arch::memory { namespace { - static std::optional frame_allocator; + std::optional static frame_allocator; auto create_frame_allocator(multiboot::memory_information const & memory_information) -> allocator::area_frame_allocator & @@ -54,7 +54,7 @@ namespace teachos::arch::memory auto initialize_memory_management() -> void { - static bool has_been_called = false; + bool static has_been_called = false; arch::exception_handling::assert(!has_been_called, "[Initialization] Memory management has already been initialized"); has_been_called = true; diff --git a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp index f5d126b..3105120 100644 --- a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp +++ b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp @@ -2,7 +2,10 @@ namespace teachos::arch::memory::multiboot { - auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool + { + return (flags & other) == other; + } auto elf_section_header::is_null() const -> bool { diff --git a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp index 0113869..930588d 100644 --- a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp @@ -4,18 +4,21 @@ namespace teachos::arch::memory::paging { namespace { - paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + constexpr paging::virtual_address PAGE_TABLE_LEVEL_4_ADDRESS = 0xffff'ffff'ffff'f000; } auto active_page_table::create_or_get() -> active_page_table & { - static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), + page_table_handle static active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), page_table_handle::LEVEL4}; - static active_page_table active_page{active_handle}; + active_page_table static 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::operator[](std::size_t index) -> entry & + { + return active_handle[index]; + } auto active_page_table::translate_address(virtual_address address) -> std::optional { diff --git a/arch/x86_64/pre/src/memory/paging/page_entry.cpp b/arch/x86_64/pre/src/memory/paging/page_entry.cpp index 57045ca..ec45068 100644 --- a/arch/x86_64/pre/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/pre/src/memory/paging/page_entry.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::memory::paging { namespace { - std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; + constexpr std::size_t PHYSICAL_ADDRESS_MASK = 0x000f'ffff'ffff'f000; } // namespace entry::entry(uint64_t flags) @@ -33,11 +33,20 @@ namespace teachos::arch::memory::paging } } - auto entry::is_unused() const -> bool { return flags == 0U; } + auto entry::is_unused() const -> bool + { + return flags == 0U; + } - auto entry::set_unused() -> void { flags = 0U; } + auto entry::set_unused() -> void + { + flags = 0U; + } - auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_user_accessible() -> void + { + flags |= entry::USER_ACCESSIBLE; + } auto entry::calculate_pointed_to_frame() const -> std::optional { @@ -49,7 +58,10 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + 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 { @@ -59,5 +71,8 @@ namespace teachos::arch::memory::paging flags = frame.start_address() | additional_flags.to_ulong(); } - auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } + 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/pre/src/memory/paging/page_table.cpp b/arch/x86_64/pre/src/memory/paging/page_table.cpp index eb11810..e79c3e5 100644 --- a/arch/x86_64/pre/src/memory/paging/page_table.cpp +++ b/arch/x86_64/pre/src/memory/paging/page_table.cpp @@ -96,9 +96,15 @@ namespace teachos::arch::memory::paging "[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::zero_entries() -> void + { + table->zero_entries(); + } - auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } + 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 { @@ -113,9 +119,15 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto page_table_handle::get_level() const -> page_table_handle::level { return table_level; } + 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 page_table_handle::operator[](std::size_t index) -> entry & + { + return table->operator[](index); + } auto operator--(page_table_handle::level & value) -> page_table_handle::level & { diff --git a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp index d374156..8d34918 100644 --- a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp @@ -6,12 +6,15 @@ namespace teachos::arch::memory::paging { auto virtual_page::containing_address(virtual_address address) -> virtual_page { - exception_handling::assert(address < 0x00008000'00000000 || address >= 0xffff8000'00000000, + exception_handling::assert(address < 0x0000'8000'0000'0000 || address >= 0xffff'8000'0000'0000, "[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::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 { diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp index 9a3df0e..70172c9 100644 --- a/arch/x86_64/src/boot/initialize_runtime.cpp +++ b/arch/x86_64/src/boot/initialize_runtime.cpp @@ -16,7 +16,9 @@ extern "C" auto constructors = std::span{&__ctors_start, &__ctors_end}; auto initializers = std::span{&__init_array_start, &__init_array_end}; - auto apply_invoke = [](auto invokable) { return std::invoke(invokable); }; + auto apply_invoke = [](auto invokable) { + return std::invoke(invokable); + }; std::ranges::for_each(constructors, apply_invoke); std::ranges::for_each(initializers, apply_invoke); diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 13103c7..a0579a3 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -12,12 +12,12 @@ namespace teachos::memory::x86_64 { namespace { - auto constexpr last_frame(multiboot2::memory_map::region const & region) + constexpr auto last_frame(multiboot2::memory_map::region const & region) { return frame::containing(physical_address{region.base + region.size_in_B - 1}); } - auto constexpr falls_within(frame const & candidate, frame const & start, frame const & end) + constexpr auto falls_within(frame const & candidate, frame const & start, frame const & end) { return candidate >= start && candidate <= end; } diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 8f78ea9..8aa809f 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -17,8 +17,8 @@ namespace teachos::vga::x86_64::text { auto constinit buffer_offset = std::ptrdiff_t{}; - auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; - auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; + constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; auto write_char(char code_point, attribute attribute) -> void { diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp index 585807a..63301aa 100644 --- a/kapi/include/kapi/memory/address.hpp +++ b/kapi/include/kapi/memory/address.hpp @@ -20,20 +20,24 @@ namespace teachos::memory { constexpr explicit address(std::uintptr_t value) noexcept : m_value{value} - { - } + {} explicit address(std::byte * pointer) noexcept : m_value{std::bit_cast(pointer)} + {} + + explicit operator std::byte *() const noexcept { + return std::bit_cast(m_value); } - explicit operator std::byte *() const noexcept { return std::bit_cast(m_value); } + constexpr auto operator<=>(address const &) const noexcept -> std::strong_ordering = default; + constexpr auto operator==(address const &) const noexcept -> bool = default; - auto constexpr operator<=>(address const &) const noexcept -> std::strong_ordering = default; - auto constexpr operator==(address const &) const noexcept -> bool = default; - - auto constexpr raw() const noexcept -> std::uintptr_t { return m_value; } + constexpr auto raw() const noexcept -> std::uintptr_t + { + return m_value; + } private: std::uintptr_t m_value{}; diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp index 8bcf79f..a208f28 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/include/kapi/memory/frame.hpp @@ -19,8 +19,7 @@ namespace teachos::memory explicit constexpr frame(std::size_t number) : m_number{number} - { - } + {} /** * @brief Returns the physical frame the given address is contained in. @@ -28,7 +27,7 @@ namespace teachos::memory * @param address Physical address we want to get the corresponding physical frame for. * @return Frame the given address is contained in. */ - auto constexpr static containing(physical_address address) noexcept -> frame + constexpr auto static containing(physical_address address) noexcept -> frame { return frame{address.raw() / PLATFORM_FRAME_SIZE}; } @@ -38,7 +37,7 @@ namespace teachos::memory * * @return Start address of the physical frame. */ - auto constexpr start_address() const noexcept -> physical_address + constexpr auto start_address() const noexcept -> physical_address { return physical_address{m_number * PLATFORM_FRAME_SIZE}; } @@ -49,14 +48,17 @@ namespace teachos::memory * @param offset * @return A new frame n frames after this one. */ - auto constexpr operator+(std::size_t n) const noexcept -> frame { return frame{m_number + n}; } + constexpr auto operator+(std::size_t n) const noexcept -> frame + { + return frame{m_number + n}; + } /** * @brief Increment this frame to refer to the next one, returning a copy. * * @return Copy of the incremented underlying frame number. */ - auto constexpr operator++(int) noexcept -> frame + constexpr auto operator++(int) noexcept -> frame { auto copy = *this; ++*this; @@ -68,7 +70,7 @@ namespace teachos::memory * * @return Reference to the incremented underlying frame number. */ - auto constexpr operator++() noexcept -> frame & + constexpr auto operator++() noexcept -> frame & { ++m_number; return *this; @@ -77,12 +79,12 @@ namespace teachos::memory /** * @brief Check if this frame refers to the same frame as @p other. */ - auto constexpr operator==(frame const & other) const noexcept -> bool = default; + constexpr auto operator==(frame const & other) const noexcept -> bool = default; /** * @brief Lexicographically compare this frame to @p other. */ - auto constexpr operator<=>(frame const & other) const noexcept -> std::strong_ordering = default; + constexpr auto operator<=>(frame const & other) const noexcept -> std::strong_ordering = default; private: std::size_t m_number{}; diff --git a/kapi/src/cio.cpp b/kapi/src/cio.cpp index aa26d49..e8490e9 100644 --- a/kapi/src/cio.cpp +++ b/kapi/src/cio.cpp @@ -18,12 +18,24 @@ namespace teachos::cio return std::exchange(active_device, &device); } - auto print(std::string_view text) -> void { active_device->write(text); } + auto print(std::string_view text) -> void + { + active_device->write(text); + } - auto println(std::string_view text) -> void { active_device->writeln(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 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); } + 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/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp index d41b165..251c187 100644 --- a/libs/kstd/include/kstd/bits/shared_ptr.hpp +++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp @@ -39,7 +39,7 @@ namespace kstd * @param other The shared_ptr to copy from. */ [[gnu::section(".stl_text")]] - shared_ptr(const shared_ptr & other) + shared_ptr(shared_ptr const & other) : pointer(other.pointer) , ref_count(other.ref_count) { @@ -72,7 +72,7 @@ namespace kstd * @return Reference to this shared pointer. */ [[gnu::section(".stl_text")]] - shared_ptr & operator=(const shared_ptr & other) + shared_ptr & operator=(shared_ptr const & other) { if (this != &other) { @@ -216,7 +216,7 @@ namespace kstd * @brief Defaulted three-way comparator operator. */ [[gnu::section(".stl_text")]] - auto operator<=>(const shared_ptr & other) const = default; + auto operator<=>(shared_ptr const & other) const = default; private: /** diff --git a/libs/kstd/include/kstd/bits/unique_ptr.hpp b/libs/kstd/include/kstd/bits/unique_ptr.hpp index 1932913..5f54848 100644 --- a/libs/kstd/include/kstd/bits/unique_ptr.hpp +++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp @@ -38,12 +38,12 @@ namespace kstd /** * @brief Deleted copy constructor to enforce unique ownership. */ - unique_ptr(const unique_ptr &) = delete; + unique_ptr(unique_ptr const &) = delete; /** * @brief Deleted copy assignment operator to enforce unique ownership. */ - auto operator=(const unique_ptr &) -> unique_ptr & = delete; + auto operator=(unique_ptr const &) -> unique_ptr & = delete; /** * @brief Move constructor. @@ -167,7 +167,7 @@ namespace kstd * @brief Defaulted three-way comparator operator. */ [[gnu::section(".stl_text")]] - auto operator<=>(const unique_ptr & other) const = default; + auto operator<=>(unique_ptr const & other) const = default; private: T * pointer; ///< The managed pointer. diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp index fe1bc95..752e616 100644 --- a/libs/kstd/src/libc/stdlib.cpp +++ b/libs/kstd/src/libc/stdlib.cpp @@ -5,7 +5,10 @@ namespace kstd::libc extern "C" { - [[noreturn]] auto abort() -> void { kstd::os::abort(); } + [[noreturn]] auto abort() -> void + { + kstd::os::abort(); + } } } // 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 index c6b3847..a42aedc 100644 --- a/libs/kstd/src/libc/string.cpp +++ b/libs/kstd/src/libc/string.cpp @@ -6,7 +6,7 @@ namespace kstd::libc extern "C" { - auto strlen(const char * string) -> std::size_t + auto strlen(char const * string) -> std::size_t { return std::distance(string, std::ranges::find(string, nullptr, '\0')); } diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp index 137ebc0..da1357f 100644 --- a/libs/kstd/src/mutex.cpp +++ b/libs/kstd/src/mutex.cpp @@ -10,7 +10,13 @@ namespace kstd } } - auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } + auto mutex::try_lock() -> bool + { + return !locked.exchange(true, std::memory_order_acquire); + } - auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } + auto mutex::unlock() -> void + { + locked.store(false, std::memory_order_release); + } } // namespace kstd diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp index 30d52d0..0f6b82f 100644 --- a/libs/multiboot2/include/multiboot2/constants.hpp +++ b/libs/multiboot2/include/multiboot2/constants.hpp @@ -13,7 +13,7 @@ namespace multiboot2 using impl::memory_type; using impl::tag_id; - auto constexpr inline header_magic = std::uint32_t{0xe85250d6}; + constexpr auto inline header_magic = std::uint32_t{0xe852'50d6}; } // namespace multiboot2 diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index a5f2e14..3cda162 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -10,7 +10,7 @@ namespace multiboot2::impl template struct tag_data { - auto constexpr inline static id = Id; + constexpr auto static inline id = Id; }; /** @@ -94,7 +94,10 @@ namespace multiboot2::impl /** * @brief Check if the memory described by this region is available for use. */ - auto constexpr available() const noexcept { return type == memory_type::AVAILABLE; } + constexpr auto available() const noexcept + { + return type == memory_type::AVAILABLE; + } /** * @brief Start address of this region diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index e82326d..f8955cb 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -23,16 +23,21 @@ namespace multiboot2::impl constexpr explicit information_iterator(impl::tag_header const * offset) : m_current(offset) - { - } + {} - auto constexpr operator==(information_iterator const &) const noexcept -> bool = default; + constexpr auto operator==(information_iterator const &) const noexcept -> bool = default; - auto constexpr operator*() const noexcept -> reference { return *(m_current.value()); } + constexpr auto operator*() const noexcept -> reference + { + return *(m_current.value()); + } - auto constexpr operator->() const noexcept -> pointer { return m_current.value(); } + constexpr auto operator->() const noexcept -> pointer + { + return m_current.value(); + } - auto constexpr operator++() noexcept -> information_iterator & + constexpr auto operator++() noexcept -> information_iterator & { if (m_current) { @@ -48,7 +53,7 @@ namespace multiboot2::impl return *this; } - auto constexpr operator++(int) noexcept -> information_iterator + constexpr auto operator++(int) noexcept -> information_iterator { auto copy = *this; ++(*this); diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index f7471a4..f151b54 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -18,24 +18,31 @@ namespace multiboot2::impl tag_header() : m_id{} , m_size{} - { - } + {} tag_header(tag_header const * data) : tag_header{*data} + {} + + auto full_size() const noexcept -> std::size_t { + return (m_size + 7) & (~7); } - auto full_size() const noexcept -> std::size_t { return (m_size + 7) & (~7); } - - auto information_id() const noexcept -> impl::information_id const & { return m_id; } + auto information_id() const noexcept -> impl::information_id const & + { + return m_id; + } auto next() const noexcept -> tag_header const * { return std::bit_cast(std::bit_cast(this) + full_size()); } - auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } + auto unaligned_size() const noexcept -> std::uint32_t + { + return m_size; + } protected: impl::information_id const m_id; @@ -51,22 +58,19 @@ namespace multiboot2::impl tag() : tag_header{} , Data{} - { - } + {} explicit tag(tag_header const * header) requires(sizeof(tag) > sizeof(tag_header)) : tag_header{header} , Data{*std::bit_cast(header + 1)} - { - } + {} explicit tag(tag_header const * header) requires(sizeof(tag) == sizeof(tag_header)) : tag_header{header} , Data{} - { - } + {} }; /** @@ -80,14 +84,12 @@ namespace multiboot2::impl vla_tag() : tag{} , m_vla{} - { - } + {} explicit vla_tag(tag_header const * header) : tag{header} , m_vla{vla_start(header), vla_size(header)} - { - } + {} protected: auto static vla_start(tag_header const * header) noexcept -> VlaData * diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 04ba183..ac03069 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -41,7 +41,10 @@ namespace multiboot2 /** * @brief The command line string */ - auto string() const noexcept -> range_type { return m_vla; } + auto string() const noexcept -> range_type + { + return m_vla; + } }; /** @@ -53,7 +56,10 @@ namespace multiboot2 using iterator = range_type::iterator; - auto data() const noexcept -> range_type { return m_vla; } + auto data() const noexcept -> range_type + { + return m_vla; + } }; /** @@ -66,7 +72,10 @@ namespace multiboot2 /** * @brief The name of the bootloader */ - auto string() const noexcept -> std::string_view { return m_vla; } + auto string() const noexcept -> std::string_view + { + return m_vla; + } }; /** @@ -78,14 +87,23 @@ namespace multiboot2 using iterator = range_type::iterator; - auto begin() const noexcept -> iterator { return regions().begin(); } + auto begin() const noexcept -> iterator + { + return regions().begin(); + } - auto end() const noexcept -> iterator { return regions().end(); } + auto end() const noexcept -> iterator + { + return regions().end(); + } /** * @brief The available memory regions */ - auto regions() const noexcept -> range_type { return m_vla; } + auto regions() const noexcept -> range_type + { + return m_vla; + } }; struct information_view @@ -95,13 +113,22 @@ namespace multiboot2 using pointer = impl::information_iterator::pointer; using reference = impl::information_iterator::reference; - auto size_bytes() const noexcept -> std::size_t { return m_size; } + auto size_bytes() const noexcept -> std::size_t + { + return m_size; + } // Range access - auto begin() const noexcept -> iterator { return iterator{&m_tags}; } + auto begin() const noexcept -> iterator + { + return iterator{&m_tags}; + } - auto end() const noexcept -> iterator { return iterator{}; } + auto end() const noexcept -> iterator + { + return iterator{}; + } // Tag access @@ -111,36 +138,69 @@ namespace multiboot2 return get().has_value(); } - auto maybe_basic_memory() const noexcept -> std::optional { return get(); } + auto maybe_basic_memory() const noexcept -> std::optional + { + return get(); + } - auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } + auto basic_memory() const -> basic_memory + { + return maybe_basic_memory().value(); + } auto maybe_bios_boot_device() const noexcept -> std::optional { return get(); } - auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } + auto bios_boot_device() const -> bios_boot_device + { + return maybe_bios_boot_device().value(); + } - auto maybe_command_line() const noexcept -> std::optional { return get(); } + auto maybe_command_line() const noexcept -> std::optional + { + return get(); + } - auto command_line() const -> command_line { return maybe_command_line().value(); } + auto command_line() const -> command_line + { + return maybe_command_line().value(); + } - auto maybe_elf_symbols() const noexcept -> std::optional { return get(); } + auto maybe_elf_symbols() const noexcept -> std::optional + { + return get(); + } - auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } + auto elf_symbols() const -> elf_symbols + { + return maybe_elf_symbols().value(); + } - auto maybe_loader_name() const noexcept -> std::optional { return get(); } + auto maybe_loader_name() const noexcept -> std::optional + { + return get(); + } - auto loader_name() const -> loader_name { return maybe_loader_name().value(); } + auto loader_name() const -> loader_name + { + return maybe_loader_name().value(); + } - auto maybe_memory_map() const noexcept -> std::optional { return get(); } + auto maybe_memory_map() const noexcept -> std::optional + { + return get(); + } - auto memory_map() const -> memory_map { return maybe_memory_map().value(); } + auto memory_map() const -> memory_map + { + return maybe_memory_map().value(); + } private: template - auto constexpr get() const noexcept -> std::optional + constexpr auto get() const noexcept -> std::optional { if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); found != end()) -- cgit v1.2.3 From 7b9df8bec5038e0316540d2397df632fb14c9169 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 17:01:22 +0100 Subject: chore: configure clang-tidy --- .clang-tidy | 5 +++ .vscode/settings.json | 11 +++++- .../include/x86_64/memory/region_allocator.hpp | 8 ++--- arch/x86_64/include/x86_64/vga/crtc.hpp | 4 +-- arch/x86_64/include/x86_64/vga/text.hpp | 26 +++++++++----- arch/x86_64/src/cpu/registers.cpp | 4 +-- arch/x86_64/src/kapi/cio.cpp | 1 + arch/x86_64/src/kapi/memory.cpp | 14 +++++--- arch/x86_64/src/vga/text.cpp | 7 ++-- cmake/Platforms/x86_64.cmake | 1 + kapi/include/kapi/cio.hpp | 3 ++ kapi/include/kapi/memory/address.hpp | 2 +- kapi/include/kapi/memory/frame.hpp | 4 +-- kapi/include/kapi/memory/frame_allocator.hpp | 2 ++ kapi/src/cio.cpp | 3 +- libs/kstd/include/kstd/asm_ptr | 42 ++++++++++++++++------ libs/kstd/include/kstd/bits/shared_ptr.hpp | 2 +- libs/kstd/include/kstd/mutex | 17 +++++++-- libs/kstd/include/kstd/stack | 32 ++++++----------- libs/kstd/include/kstd/vector | 9 +++-- libs/kstd/src/libc/stdlib.cpp | 5 +++ 21 files changed, 133 insertions(+), 69 deletions(-) create mode 100644 .clang-tidy diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..64699bf --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,5 @@ +Checks: + - '-clang-diagnostic-*' + - 'clang-analyzer-*' + - 'cppcoreguidelines-*' + - 'modernize-*' \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 91b307a..8cee879 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,5 +20,14 @@ "editor.rulers": [ 80 ] - } + }, + "cSpell.words": [ + "crtc", + "invlpg", + "kapi", + "kstd", + "NOLINTNEXTLINE", + "rvalues", + "TeachOS" + ] } \ 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 index 913b0bb..4a18a0f 100644 --- a/arch/x86_64/include/x86_64/memory/region_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -66,10 +66,10 @@ namespace teachos::memory::x86_64 frame m_next_frame; ///< The physical_frame after the last allocated one. std::optional m_current_region; ///< The memory region currently allocated from multiboot2::memory_map m_memory_map; ///< The boot loader supplied memory map. - frame const m_kernel_start; ///< The start address of the kernel code in memory. - frame const m_kernel_end; ///< The end address of the kernel code in memory. - frame const m_multiboot_start; ///< The start address of the multiboot code in memory. - frame const m_multiboot_end; ///< The end address of the multiboot code in memory. + frame m_kernel_start; ///< The start address of the kernel code in memory. + frame m_kernel_end; ///< The end address of the kernel code in memory. + frame m_multiboot_start; ///< The start address of the multiboot code in memory. + frame m_multiboot_end; ///< The end address of the multiboot code in memory. }; } // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/include/x86_64/vga/crtc.hpp b/arch/x86_64/include/x86_64/vga/crtc.hpp index be72ac4..8bdc12d 100644 --- a/arch/x86_64/include/x86_64/vga/crtc.hpp +++ b/arch/x86_64/include/x86_64/vga/crtc.hpp @@ -10,12 +10,12 @@ namespace teachos::vga::x86_64::crtc /** * @brief The address port of the CRT Controller. */ - using address = io::x86_64::port<0x3d4, 1>; + using address = io::x86_64::port<0x3d4, 1>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) /** * @brief The data port of the CRT Controller. */ - using data = io::x86_64::port<0x3d5, 1>; + using data = io::x86_64::port<0x3d5, 1>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) namespace registers { diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index 858350f..d8919bf 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -54,7 +54,7 @@ namespace teachos::vga::x86_64::text { 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. + color background_color : 3; ///< The background color of the cell. enum background_flag background_flag : 1; ///< The background color modification flag of the cell. }; @@ -68,26 +68,34 @@ namespace teachos::vga::x86_64::text /** * @brief Make the affected cell display with a gray foreground and black background. */ - [[maybe_unused]] constexpr auto gray_on_black = - attribute{color::gray, foreground_flag::none, color::black, background_flag::none}; + [[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{color::green, foreground_flag::none, color::black, background_flag::none}; + [[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{color::red, foreground_flag::none, color::black, background_flag::none}; + [[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{color::gray, foreground_flag::intense, color::red, background_flag::none}; + [[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 diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp index 8646829..d59776b 100644 --- a/arch/x86_64/src/cpu/registers.cpp +++ b/arch/x86_64/src/cpu/registers.cpp @@ -6,7 +6,7 @@ namespace teachos::cpu::x86_64 { auto read_control_register(control_register cr) -> uint64_t { - uint64_t current_value; + uint64_t current_value{}; switch (cr) { case control_register::cr0: @@ -59,6 +59,6 @@ namespace teachos::cpu::x86_64 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::type>(flag) | cr0); + write_control_register(control_register::cr0, static_cast>(flag) | cr0); } } // namespace teachos::cpu::x86_64 diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp index eb0142a..456477a 100644 --- a/arch/x86_64/src/kapi/cio.cpp +++ b/arch/x86_64/src/kapi/cio.cpp @@ -5,6 +5,7 @@ namespace teachos::cio { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto static constinit vga_device = std::optional{}; auto init() -> void diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 61d462f..e05fde9 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -19,19 +19,23 @@ namespace teachos::memory namespace { + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) auto constinit is_initialized = std::atomic_flag{}; auto constinit allocator = static_cast(nullptr); + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); auto map = mbi->memory_map(); - return {std::make_pair(physical_address{&boot::x86_64::_start_physical}, - physical_address{&boot::x86_64::_end_physical}), - std::make_pair(physical_address{std::bit_cast(mbi)}, - physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), - map}; + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, + physical_address{&boot::x86_64::_end_physical}), + .mbi_range = std::make_pair(physical_address{std::bit_cast(mbi)}, + physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), + .memory_map = map}; + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) }; auto create_early_frame_allocator() diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 8aa809f..0e0d353 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -15,10 +15,12 @@ namespace teachos::vga::x86_64::text namespace { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit buffer_offset = std::ptrdiff_t{}; constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + constexpr auto CURSOR_ENABLED_BIT = 5U; auto write_char(char code_point, attribute attribute) -> void { @@ -29,12 +31,13 @@ namespace teachos::vga::x86_64::text auto device::clear(attribute attribute) -> void { buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', std::bit_cast(attribute)}); + std::ranges::fill_n(vga_buffer_pointer.get(), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT, + std::pair{' ', std::bit_cast(attribute)}); } auto device::cursor(bool enabled) -> void { - auto cursor_disable_byte = std::byte{!enabled} << 5; + 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); diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index afdc0ec..23287de 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -19,6 +19,7 @@ set(CMAKE_CXX_FLAGS_INIT "-fno-pie" "-fno-rtti" "-fno-exceptions" + "-fno-use-cxa-atexit" "-ffunction-sections" "-fdata-sections" ) diff --git a/kapi/include/kapi/cio.hpp b/kapi/include/kapi/cio.hpp index 6b93638..a01af08 100644 --- a/kapi/include/kapi/cio.hpp +++ b/kapi/include/kapi/cio.hpp @@ -6,8 +6,11 @@ namespace teachos::cio { + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) struct output_device { + virtual ~output_device() = default; + auto virtual write(std::string_view text [[maybe_unused]]) -> void {} auto virtual writeln(std::string_view text [[maybe_unused]]) -> void {} diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp index 63301aa..359b5ec 100644 --- a/kapi/include/kapi/memory/address.hpp +++ b/kapi/include/kapi/memory/address.hpp @@ -34,7 +34,7 @@ namespace teachos::memory constexpr auto operator<=>(address const &) const noexcept -> std::strong_ordering = default; constexpr auto operator==(address const &) const noexcept -> bool = default; - constexpr auto raw() const noexcept -> std::uintptr_t + [[nodiscard]] constexpr auto raw() const noexcept -> std::uintptr_t { return m_value; } diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp index a208f28..63b1e70 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/include/kapi/memory/frame.hpp @@ -3,10 +3,8 @@ #include "kapi/memory/address.hpp" -#include #include #include -#include namespace teachos::memory { @@ -37,7 +35,7 @@ namespace teachos::memory * * @return Start address of the physical frame. */ - constexpr auto start_address() const noexcept -> physical_address + [[nodiscard]] constexpr auto start_address() const noexcept -> physical_address { return physical_address{m_number * PLATFORM_FRAME_SIZE}; } diff --git a/kapi/include/kapi/memory/frame_allocator.hpp b/kapi/include/kapi/memory/frame_allocator.hpp index f9393ee..22102a6 100644 --- a/kapi/include/kapi/memory/frame_allocator.hpp +++ b/kapi/include/kapi/memory/frame_allocator.hpp @@ -8,8 +8,10 @@ namespace teachos::memory { + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) struct frame_allocator { + virtual ~frame_allocator() = default; virtual auto allocate() -> std::optional = 0; virtual auto release(frame frame) -> void = 0; }; diff --git a/kapi/src/cio.cpp b/kapi/src/cio.cpp index e8490e9..210e58e 100644 --- a/kapi/src/cio.cpp +++ b/kapi/src/cio.cpp @@ -5,8 +5,9 @@ namespace teachos::cio { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit null_device = output_device{}; - + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit active_device = &null_device; auto set_output_device(output_device & device) -> std::optional diff --git a/libs/kstd/include/kstd/asm_ptr b/libs/kstd/include/kstd/asm_ptr index e9072e2..e8636c3 100644 --- a/libs/kstd/include/kstd/asm_ptr +++ b/libs/kstd/include/kstd/asm_ptr @@ -23,28 +23,50 @@ namespace kstd asm_ptr() = delete; asm_ptr(asm_ptr const &) = delete; asm_ptr(asm_ptr &&) = delete; + ~asm_ptr() = delete; - auto constexpr operator=(asm_ptr const &) = delete; - auto constexpr operator=(asm_ptr &&) = delete; + constexpr auto operator=(asm_ptr const &) = delete; + constexpr auto operator=(asm_ptr &&) = delete; - auto get() const noexcept -> pointer { return m_ptr; } + auto get() const noexcept -> pointer + { + return m_ptr; + } - auto constexpr operator+(std::ptrdiff_t offset) const noexcept -> pointer + constexpr auto operator+(std::ptrdiff_t offset) const noexcept -> pointer { return std::bit_cast(m_ptr) + offset; } - auto constexpr operator*() noexcept -> reference { return *(std::bit_cast(m_ptr)); } + constexpr auto operator*() noexcept -> reference + { + return *(std::bit_cast(m_ptr)); + } - auto constexpr operator*() const noexcept -> const_reference { return *(std::bit_cast(m_ptr)); } + constexpr auto operator*() const noexcept -> const_reference + { + return *(std::bit_cast(m_ptr)); + } - auto constexpr operator[](std::ptrdiff_t offset) noexcept -> reference { return *(*this + offset); } + constexpr auto operator[](std::ptrdiff_t offset) noexcept -> reference + { + return *(*this + offset); + } - auto constexpr operator[](std::ptrdiff_t offset) const noexcept -> const_reference { return *(*this + offset); } + constexpr auto operator[](std::ptrdiff_t offset) const noexcept -> const_reference + { + return *(*this + offset); + } - auto constexpr operator->() noexcept -> pointer { return m_ptr; } + constexpr auto operator->() noexcept -> pointer + { + return m_ptr; + } - auto constexpr operator->() const noexcept -> const_pointer { return m_ptr; } + constexpr auto operator->() const noexcept -> const_pointer + { + return m_ptr; + } private: pointer m_ptr; diff --git a/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp index 251c187..4bcf499 100644 --- a/libs/kstd/include/kstd/bits/shared_ptr.hpp +++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp @@ -220,7 +220,7 @@ namespace kstd 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 diff --git a/libs/kstd/include/kstd/mutex b/libs/kstd/include/kstd/mutex index cf8549f..6ae3adf 100644 --- a/libs/kstd/include/kstd/mutex +++ b/libs/kstd/include/kstd/mutex @@ -24,12 +24,23 @@ namespace kstd /** * @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). diff --git a/libs/kstd/include/kstd/stack b/libs/kstd/include/kstd/stack index 8c702cf..8cd208a 100644 --- a/libs/kstd/include/kstd/stack +++ b/libs/kstd/include/kstd/stack @@ -1,8 +1,7 @@ #ifndef KSTD_STACK_HPP #define KSTD_STACK_HPP -#include "kstd/vector.hpp" - +#include "kstd/vector" #include namespace kstd @@ -29,8 +28,12 @@ namespace kstd */ 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. @@ -61,11 +64,11 @@ namespace kstd /** * @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 initalizer_list) - : _container(initalizer_list) + explicit stack(std::initializer_list elements) + : _container(elements) { // Nothing to do. } @@ -85,21 +88,6 @@ namespace kstd // Nothing to do. } - /** - * @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 & operator=(stack const & other) - { - _container = other; - } - /** * @brief Destructor. */ @@ -194,7 +182,7 @@ namespace kstd } /** - * @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. */ diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector index 1009e81..9d96eb8 100644 --- a/libs/kstd/include/kstd/vector +++ b/libs/kstd/include/kstd/vector @@ -29,7 +29,7 @@ namespace kstd 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. @@ -99,7 +99,7 @@ namespace kstd * @return Newly created copy. */ [[gnu::section(".stl_text")]] - vector & operator=(vector const & other) + auto operator=(vector const & other) -> vector & { delete[] _data; _size = other._size; @@ -112,7 +112,10 @@ namespace kstd /** * @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 diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp index 752e616..a0f062a 100644 --- a/libs/kstd/src/libc/stdlib.cpp +++ b/libs/kstd/src/libc/stdlib.cpp @@ -9,6 +9,11 @@ namespace kstd::libc { 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 -- cgit v1.2.3 From 5e9b7dd3dbc194ffa583e9efaab1aef1b6792d97 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 30 Oct 2025 08:58:58 +0100 Subject: ide: disable gsl::owner checks --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index 64699bf..30729e9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,4 +2,5 @@ Checks: - '-clang-diagnostic-*' - 'clang-analyzer-*' - 'cppcoreguidelines-*' + - '-cppcoreguidelines-owning-memory' - 'modernize-*' \ No newline at end of file -- cgit v1.2.3 From 78f0df1cf849af8b0ade40a8ebcffd7fb53635cb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 30 Oct 2025 15:59:48 +0100 Subject: libs: begin ELF support implementation --- .clang-format | 10 +++++---- cmake/Platforms/x86_64.cmake | 2 +- libs/CMakeLists.txt | 1 + libs/elf/CMakeLists.txt | 19 ++++++++++++++++ libs/elf/include/elf/format.hpp | 15 +++++++++++++ libs/elf/include/elf/section_header.hpp | 23 ++++++++++++++++++++ libs/multiboot2/CMakeLists.txt | 8 +++++++ libs/multiboot2/include/multiboot2/information.hpp | 25 ++++++++++++++-------- 8 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 libs/elf/CMakeLists.txt create mode 100644 libs/elf/include/elf/format.hpp create mode 100644 libs/elf/include/elf/section_header.hpp diff --git a/.clang-format b/.clang-format index 6d3fa9d..a47e396 100644 --- a/.clang-format +++ b/.clang-format @@ -55,13 +55,15 @@ DerivePointerAlignment: "false" FixNamespaceComments: "true" IncludeBlocks: Regroup IncludeCategories: - - Regex: kapi/[[:alnum:]._\/]+\.hpp + - Regex: 'kapi/[[:alnum:]._\/]+\.hpp' Priority: 100 - - Regex: x86_64/[[:alnum:]._\/]+\.hpp + - Regex: 'x86_64/[[:alnum:]._\/]+\.hpp' Priority: 110 - - Regex: "[[:alnum:]._\\/]+\\.hpp" + - Regex: '"[[:alnum:]._\/]+\.hpp"' Priority: 300 - - Regex: <[[:alnum:]._]+(?!\.(h|hpp))> + - Regex: '<[[:alnum:]._\/]+\.hpp>' + Priority: 600 + - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' Priority: 900 IndentCaseLabels: "true" IndentPPDirectives: None diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index 23287de..b17fec8 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -10,7 +10,7 @@ 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}-gcc" REQUIRED) +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 diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index b2dbf86..58d9796 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -1,2 +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..0ff5e4b --- /dev/null +++ b/libs/elf/include/elf/section_header.hpp @@ -0,0 +1,23 @@ +#ifndef ELF_SECTION_HEADER_HPP +#define ELF_SECTION_HEADER_HPP + +#include "format.hpp" + +#include + +namespace elf +{ + + enum struct section_header_type : std::uint32_t + { + }; + + template + struct section_header + { + std::uint32_t name_offset; + section_header_type type; + }; +} // namespace elf + +#endif \ No newline at end of file diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index 7b9e58a..350a996 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -17,3 +17,11 @@ target_sources("multiboot2" INTERFACE 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/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index ac03069..d2b4c98 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -5,6 +5,9 @@ #include "impl/iterator.hpp" #include "impl/tag.hpp" +#include +#include + #include #include #include @@ -50,15 +53,17 @@ namespace multiboot2 /** * @copydoc multiboot2::impl::elf_symbols_data */ - struct elf_symbols : impl::vla_tag + template + struct elf_symbols : impl::vla_tag const, std::span> { - using vla_tag::vla_tag; + using base = impl::vla_tag const, std::span>; + using base::base; - using iterator = range_type::iterator; + using iterator = base::range_type::iterator; - auto data() const noexcept -> range_type + auto data() const noexcept -> base::range_type { - return m_vla; + return this->m_vla; } }; @@ -168,14 +173,16 @@ namespace multiboot2 return maybe_command_line().value(); } - auto maybe_elf_symbols() const noexcept -> std::optional + template + auto maybe_elf_symbols() const noexcept -> std::optional> { - return get(); + return get>(); } - auto elf_symbols() const -> elf_symbols + template + auto elf_symbols() const -> elf_symbols { - return maybe_elf_symbols().value(); + return maybe_elf_symbols().value(); } auto maybe_loader_name() const noexcept -> std::optional -- cgit v1.2.3 From c5ff471e253b27c0d58a78a07322f63522b3e487 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 30 Oct 2025 16:01:26 +0100 Subject: chore: fix header grouping --- arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp | 1 + arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp index 540ff5c..bb8b526 100644 --- a/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/pre/include/arch/memory/heap/linked_list_allocator.hpp @@ -3,6 +3,7 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/heap/memory_block.hpp" + #include namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp index ba80918..275e5e2 100644 --- a/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/pre/include/arch/memory/multiboot/reader.hpp @@ -5,6 +5,7 @@ // #include "arch/memory/multiboot/memory_map.hpp" #include "arch/memory/multiboot/elf_symbols_section.hpp" + #include #include -- cgit v1.2.3 From b1143bde71bb029ac2bf7d08ba422fcdaedd56a6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 31 Oct 2025 07:19:16 +0100 Subject: build: enable linting --- CMakeLists.txt | 17 +++++++++++++++++ arch/x86_64/src/boot/initialize_runtime.cpp | 4 ++-- arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- arch/x86_64/src/vga/text.cpp | 6 +++--- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d45997..8e53923 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,12 @@ 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) + #[============================================================================[ # Global Build System Configuration #]============================================================================] @@ -31,6 +37,17 @@ add_compile_options( "$<$:-pedantic-errors>" ) +#[============================================================================[ +# Global Linting Configuration +#]============================================================================] + +find_program(CLANG_TIDY_EXE "clang-tidy") + +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() + #[============================================================================[ # Kernel Executable #]============================================================================] diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp index 70172c9..46dd5e4 100644 --- a/arch/x86_64/src/boot/initialize_runtime.cpp +++ b/arch/x86_64/src/boot/initialize_runtime.cpp @@ -16,8 +16,8 @@ extern "C" auto constructors = std::span{&__ctors_start, &__ctors_end}; auto initializers = std::span{&__init_array_start, &__init_array_end}; - auto apply_invoke = [](auto invokable) { - return std::invoke(invokable); + auto apply_invoke = [](auto invokable) -> void { + std::invoke(invokable); }; std::ranges::for_each(constructors, apply_invoke); diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index a0579a3..8ea76c6 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -40,10 +40,10 @@ namespace teachos::memory::x86_64 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) { return last_frame(region) >= next; }); + 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) { return lhs.base < rhs.base; }); + 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()) { diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 0e0d353..6ecffa3 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -48,7 +48,7 @@ namespace teachos::vga::x86_64::text auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; - if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT) + if (std::cmp_greater_equal(next_line, DEFAULT_TEXT_BUFFER_HEIGHT)) { auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; @@ -63,12 +63,12 @@ namespace teachos::vga::x86_64::text auto device::write(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); } auto device::writeln(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); newline(); } -- cgit v1.2.3 From 31c5f011b2c7b4cc65d4017d92c2fe0bdf7f4ba6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 31 Oct 2025 11:16:12 +0100 Subject: libs/elf: implement section headers --- libs/elf/include/elf/section_header.hpp | 66 ++++++++++++++++++++-- libs/multiboot2/include/multiboot2/information.hpp | 12 +++- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp index 0ff5e4b..73e2e7b 100644 --- a/libs/elf/include/elf/section_header.hpp +++ b/libs/elf/include/elf/section_header.hpp @@ -4,20 +4,76 @@ #include "format.hpp" #include +#include +#include namespace elf { - enum struct section_header_type : std::uint32_t - { - }; + template + constexpr auto inline section_header_size = std::numeric_limits::max(); + + template<> + constexpr auto inline section_header_size = 40uz; + + template<> + constexpr auto inline section_header_size = 64uz; template struct section_header { - std::uint32_t name_offset; - section_header_type type; + using format_uint = std::conditional_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 + }; + + 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) == section_header_size); + static_assert(sizeof(section_header) == section_header_size); } // namespace elf #endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index d2b4c98..462528d 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -176,7 +176,17 @@ namespace multiboot2 template auto maybe_elf_symbols() const noexcept -> std::optional> { - return get>(); + return get>().and_then( + [](auto x) -> std::optional> { + if (x.entry_size == elf::section_header_size) + { + return std::optional{x}; + } + else + { + return std::nullopt; + } + }); } template -- cgit v1.2.3 From 49dcbdaaca348784d7fa05e12a06123f4dc252ec Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 18 Nov 2025 18:14:30 +0100 Subject: x86_64/memory: perform slight cleanup --- arch/x86_64/include/x86_64/memory/region_allocator.hpp | 12 ++++++++++++ arch/x86_64/src/kapi/memory.cpp | 5 +---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/x86_64/memory/region_allocator.hpp b/arch/x86_64/include/x86_64/memory/region_allocator.hpp index 4a18a0f..3ddc8b6 100644 --- a/arch/x86_64/include/x86_64/memory/region_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -20,8 +20,20 @@ namespace teachos::memory::x86_64 { 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 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 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; }; diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index e05fde9..aa3eb58 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -27,15 +27,12 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); - auto map = mbi->memory_map(); - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), .mbi_range = std::make_pair(physical_address{std::bit_cast(mbi)}, physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), - .memory_map = map}; - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) + .memory_map = mbi->memory_map()}; }; auto create_early_frame_allocator() -- cgit v1.2.3 From 886c920b8c943753a56ef4893e074c5754a1aa2d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Nov 2025 14:53:15 +0100 Subject: kapi: enable default construction for addresses --- kapi/include/kapi/memory/address.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp index 359b5ec..19615e4 100644 --- a/kapi/include/kapi/memory/address.hpp +++ b/kapi/include/kapi/memory/address.hpp @@ -18,6 +18,8 @@ namespace teachos::memory template struct address { + constexpr explicit address() noexcept = default; + constexpr explicit address(std::uintptr_t value) noexcept : m_value{value} {} -- cgit v1.2.3 From a5ca21e45e9c8ead0b5895771c0b2f3fe3baf96b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Nov 2025 14:53:37 +0100 Subject: x86_64: rework control register access --- arch/x86_64/CMakeLists.txt | 3 - .../include/x86_64/cpu/impl/control_registers.hpp | 196 +++++++++++++++++++++ arch/x86_64/include/x86_64/cpu/registers.hpp | 68 +------ arch/x86_64/src/cpu/registers.cpp | 64 ------- arch/x86_64/src/kapi/memory.cpp | 3 +- arch/x86_64/src/memory/mmu.cpp | 4 +- 6 files changed, 201 insertions(+), 137 deletions(-) create mode 100644 arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp delete mode 100644 arch/x86_64/src/cpu/registers.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index a681347..9c6d818 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -17,9 +17,6 @@ target_sources("x86_64" PRIVATE "src/boot/initialize_runtime.cpp" "src/boot/multiboot.s" - # CPU intrinsics - "src/cpu/registers.cpp" - # api::kapi implementation "src/kapi/cio.cpp" "src/kapi/cpu.cpp" diff --git a/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp new file mode 100644 index 0000000..d892360 --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp @@ -0,0 +1,196 @@ +#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP + +#include "kapi/memory/address.hpp" + +#include +#include +#include + +namespace teachos::cpu::x86_64 +{ + + namespace impl + { + constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; + constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; + constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; + + template + struct control_register_with_flags + { + }; + + template + struct control_register_with_flags>> + { + using flags = ValueType; + + auto static set(ValueType value) -> void + { + auto current = Derived::read(); + current |= value; + Derived::write(current); + } + + auto static clear(ValueType value) -> void + { + auto current = Derived::read(); + current &= ~value; + Derived::write(current); + } + }; + + template + struct control_register : control_register_with_flags, ValueType> + { + [[nodiscard]] auto static read() -> ValueType + { + auto value = ValueType{}; + asm volatile((AssemblerTemplates->first) : "=r"(value)); + return value; + } + + auto static write(ValueType value) -> void + { + asm volatile((AssemblerTemplates->second) : : "r"(value)); + } + }; + + 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 + }; + + constexpr auto operator|(cr0_flags lhs, cr0_flags rhs) -> cr0_flags + { + return static_cast(static_cast>(lhs) | + static_cast>(rhs)); + } + + constexpr auto operator|=(cr0_flags & lhs, cr0_flags rhs) -> cr0_flags & + { + lhs = lhs | rhs; + return lhs; + } + + constexpr auto operator&(cr0_flags lhs, cr0_flags rhs) -> cr0_flags + { + return static_cast(static_cast>(lhs) & + static_cast>(rhs)); + } + + constexpr auto operator&=(cr0_flags & lhs, cr0_flags rhs) -> cr0_flags & + { + lhs = lhs & rhs; + return lhs; + } + + constexpr auto operator~(cr0_flags lhs) -> cr0_flags + { + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) + return static_cast(~static_cast>(lhs)); + } + + enum struct cr3_flags : std::uint64_t + { + page_level_write_through = 1uz << 0, + page_level_cache_disable = 1uz << 1, + }; + + constexpr auto operator|(cr3_flags lhs, cr3_flags rhs) -> cr3_flags + { + return static_cast(static_cast>(lhs) | + static_cast>(rhs)); + } + + constexpr auto operator|=(cr3_flags & lhs, cr3_flags rhs) -> cr3_flags & + { + lhs = lhs | rhs; + return lhs; + } + + constexpr auto operator&(cr3_flags lhs, cr3_flags rhs) -> cr3_flags + { + return static_cast(static_cast>(lhs) & + static_cast>(rhs)); + } + + constexpr auto operator&=(cr3_flags & lhs, cr3_flags rhs) -> cr3_flags & + { + lhs = lhs & rhs; + return lhs; + } + + constexpr auto operator~(cr3_flags lhs) -> cr3_flags + { + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) + return static_cast(~static_cast>(lhs)); + } + + struct cr3_value + { + constexpr cr3_value() = default; + + constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast(0)) + : m_flags{static_cast(flags)} + , m_address{static_cast(address.raw())} + {} + + [[nodiscard]] constexpr auto address() const -> memory::physical_address + { + return memory::physical_address{m_address}; + } + + constexpr auto address(memory::physical_address address) -> void + { + m_address = static_cast(address.raw()); + } + + [[nodiscard]] constexpr auto flags() const -> cr3_flags + { + return static_cast(m_flags); + } + + constexpr auto flags(cr3_flags flags) -> void + { + m_flags = static_cast(flags); + } + + private: + std::uint64_t : 3; + std::uint64_t m_flags : 2 {}; + std::uint64_t : 7; + std::uint64_t m_address : 52 {}; + }; + + } // namespace impl + + using cr0 = impl::control_register; + using cr2 = impl::control_register; + using cr3 = impl::control_register; + +} // 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 index d19acfc..7f71b95 100644 --- a/arch/x86_64/include/x86_64/cpu/registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -1,72 +1,6 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include - -namespace teachos::cpu::x86_64 -{ - - /** - * @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::cpu::x86_64 +#include "x86_64/cpu/impl/control_registers.hpp" // IWYU pragma: export #endif \ No newline at end of file diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp deleted file mode 100644 index d59776b..0000000 --- a/arch/x86_64/src/cpu/registers.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "x86_64/cpu/registers.hpp" - -#include - -namespace teachos::cpu::x86_64 -{ - 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>(flag) | cr0); - } -} // namespace teachos::cpu::x86_64 diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index aa3eb58..4766bb3 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -6,6 +6,7 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" +#include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/region_allocator.hpp" @@ -48,7 +49,7 @@ namespace teachos::memory auto enable_cpu_protections() -> void { - cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); + cpu::x86_64::cr0::clear(cpu::x86_64::cr0::flags::write_protect); // set_efer_bit(efer_flags::NXE); } } // namespace diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index e573b4e..8ec8a2e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -13,7 +13,7 @@ namespace teachos::memory::x86_64 auto tlb_flush_all() -> void { - auto current_value = cpu::read_control_register(cpu::control_register::cr3); - cpu::write_control_register(cpu::control_register::cr3, current_value); + auto paging_root = cpu::cr3::read(); + cpu::cr3::write(paging_root); } } // namespace teachos::memory::x86_64 -- cgit v1.2.3 From 7f935cdc3e57d80c4ef83760e1a616c33684271d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Nov 2025 14:55:10 +0100 Subject: x86_64: fix enabling of write protection --- arch/x86_64/src/kapi/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 4766bb3..6102bee 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -49,7 +49,7 @@ namespace teachos::memory auto enable_cpu_protections() -> void { - cpu::x86_64::cr0::clear(cpu::x86_64::cr0::flags::write_protect); + cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); // set_efer_bit(efer_flags::NXE); } } // namespace -- cgit v1.2.3 From 9ee028e52bd60affded3b90ea8dcd20c93bb5025 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 13:16:35 +0100 Subject: x86-64/kapi: reimplement ia32_efer support --- .vscode/settings.json | 5 +- .../x86_64/cpu/impl/model_specific_register.hpp | 112 +++++++++++++++++++++ arch/x86_64/include/x86_64/cpu/registers.hpp | 3 +- arch/x86_64/src/kapi/memory.cpp | 3 +- 4 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 8cee879..dcf1d1a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,11 +23,14 @@ }, "cSpell.words": [ "crtc", + "efer", "invlpg", "kapi", "kstd", "NOLINTNEXTLINE", + "rdmsr", "rvalues", - "TeachOS" + "TeachOS", + "wrmsr" ] } \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp b/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp new file mode 100644 index 0000000..8a41a8a --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp @@ -0,0 +1,112 @@ +#ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP +#define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP + +#include +#include +#include + +namespace teachos::cpu::x86_64 +{ + namespace impl + { + constexpr auto ia32_efer_number = 0xC000'0080u; + + template + struct model_specific_register_with_flags + { + }; + + template + struct model_specific_register_with_flags>> + { + using flags = ValueType; + + auto static set(flags flag) -> void + { + auto current = Derived::read(); + current |= flag; + Derived::write(current); + } + + auto static clear(flags flag) -> void + { + auto current = Derived::read(); + current &= ~flag; + Derived::write(current); + } + + auto test(flags flag) -> void + { + return Derived::read() & flag; + } + }; + + template + struct model_specific_register + : model_specific_register_with_flags, ValueType> + { + struct raw_value + { + std::uint32_t low_half; + std::uint32_t high_half; + }; + + auto static read() -> ValueType + { + auto raw = raw_value{}; + asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); + return static_cast(std::bit_cast(raw)); + } + + auto static write(ValueType value) -> void + { + auto raw = std::bit_cast(static_cast(value)); + asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); + } + }; + + enum struct ia32_efer_flags : std::uint64_t + { + syscall_enable = 1uz << 0, + ia32e_mode_enable = 1uz << 8, + ia32e_mode_active = 1uz << 10, + execute_disable_bit_enable = 1uz << 11, + }; + + constexpr auto operator|(ia32_efer_flags lhs, ia32_efer_flags rhs) -> ia32_efer_flags + { + return static_cast(static_cast>(lhs) | + static_cast>(rhs)); + } + + constexpr auto operator|=(ia32_efer_flags & lhs, ia32_efer_flags rhs) -> ia32_efer_flags & + { + lhs = lhs | rhs; + return lhs; + } + + constexpr auto operator&(ia32_efer_flags lhs, ia32_efer_flags rhs) -> ia32_efer_flags + { + return static_cast(static_cast>(lhs) & + static_cast>(rhs)); + } + + constexpr auto operator&=(ia32_efer_flags & lhs, ia32_efer_flags rhs) -> ia32_efer_flags & + { + lhs = lhs & rhs; + return lhs; + } + + constexpr auto operator~(ia32_efer_flags lhs) -> ia32_efer_flags + { + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) + return static_cast(~static_cast>(lhs)); + } + + } // namespace impl + + using i32_efer = impl::model_specific_register; + +} // 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 index 7f71b95..97cba19 100644 --- a/arch/x86_64/include/x86_64/cpu/registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include "x86_64/cpu/impl/control_registers.hpp" // IWYU pragma: export +#include "x86_64/cpu/impl/control_registers.hpp" // IWYU pragma: export +#include "x86_64/cpu/impl/model_specific_register.hpp" // IWYU pragma: export #endif \ No newline at end of file diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 6102bee..d0d966b 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -6,7 +6,6 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/region_allocator.hpp" @@ -50,7 +49,7 @@ namespace teachos::memory auto enable_cpu_protections() -> void { cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); - // set_efer_bit(efer_flags::NXE); + cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable); } } // namespace -- cgit v1.2.3 From 2b3dca0d0329b61881ffbecca0f120cfda3314fa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 13:25:12 +0100 Subject: x86_64/kapi: clean up one linter warning --- arch/x86_64/src/kapi/memory.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index d0d966b..5142a2a 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -19,10 +19,8 @@ namespace teachos::memory namespace { - // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit is_initialized = std::atomic_flag{}; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); - // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) auto create_memory_information() -> x86_64::region_allocator::memory_information { @@ -65,6 +63,7 @@ namespace teachos::memory 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."); -- cgit v1.2.3 From 1a3c20cc9ea191a862eb7e8ac55b3a69ac74ad5e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 16:59:24 +0100 Subject: x86_64/vga: rely less on magic state --- .vscode/settings.json | 2 ++ arch/x86_64/CMakeLists.txt | 24 +++++++++++++++ arch/x86_64/include/x86_64/boot/boot.hpp | 24 +++++++-------- arch/x86_64/include/x86_64/boot/ld.hpp | 9 ++++++ arch/x86_64/include/x86_64/vga/text.hpp | 11 +++++++ arch/x86_64/src/boot/entry64.s | 19 ++++++++++++ arch/x86_64/src/kapi/memory.cpp | 4 +-- arch/x86_64/src/vga/text.cpp | 50 ++++++++++++++++++-------------- kapi/CMakeLists.txt | 1 + kapi/include/kapi/boot.hpp | 11 +++++++ 10 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 kapi/include/kapi/boot.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json index dcf1d1a..4f3f047 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,9 +24,11 @@ "cSpell.words": [ "crtc", "efer", + "INTERPROCEDURAL", "invlpg", "kapi", "kstd", + "multiboot", "NOLINTNEXTLINE", "rdmsr", "rvalues", diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9c6d818..cf85b36 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -30,6 +30,30 @@ target_sources("x86_64" PRIVATE "src/vga/text.cpp" ) +target_sources("x86_64" PRIVATE + FILE_SET HEADERS + BASE_DIRS "include" + FILES + # Low-level bootstrap + "include/x86_64/boot/boot.hpp" + "include/x86_64/boot/ld.hpp" + + # Low-level CPU access + "include/x86_64/cpu/registers.hpp" + "include/x86_64/cpu/impl/control_registers.hpp" + "include/x86_64/cpu/impl/model_specific_register.hpp" + + # Low-level device I/O + "include/x86_64/device_io/port_io.hpp" + + # Memory management + "include/x86_64/memory/mmu.hpp" + "include/x86_64/memory/region_allocator.hpp" + + # VGA I/O + "include/x86_64/vga/text.hpp" +) + set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" PARENT_SCOPE diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 3a3620d..6dcd2de 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -45,26 +45,22 @@ /* clang-format on */ #else +#include "kapi/boot.hpp" // IWYU pragma: export + #include -#include +#include -namespace teachos::boot::x86_64 +namespace teachos::boot { - extern "C" + struct information { - /** - * @brief A pointer to the multiboot 2 information structure provided by the boot loader. - */ - extern kstd::asm_ptr multiboot_information_pointer; - - /** - * @brief A pointer to the VGA text mode buffer. - */ - extern kstd::asm_ptr> vga_buffer_pointer; - } -} // namespace teachos::boot::x86_64 + multiboot2::information_view const * mbi; + std::size_t vga_buffer_index; + }; + +} // namespace teachos::boot #endif diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index 104e6ee..9af3dc8 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -61,6 +61,15 @@ namespace teachos::boot::x86_64 * To use this symbol for its intended purpose, the address of it shall be taken. */ extern std::byte _end_virtual; + + /** + * @brief The first byte of the kernel's virtual address space. + * + * @details + * This symbol is defined in the kernel linker script and marks beginning of the kernel virtual address space. To + * use this symbol for its intended purpose, the address of it shall be taken. + */ + extern std::byte TEACHOS_VMA; } } // namespace teachos::boot::x86_64 diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index d8919bf..bb593e7 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -4,6 +4,7 @@ #include "kapi/cio.hpp" #include +#include #include namespace teachos::vga::x86_64::text @@ -100,6 +101,8 @@ namespace teachos::vga::x86_64::text struct device final : teachos::cio::output_device { + device(); + /** * @brief Clear the VGA text mode buffer. * @@ -134,6 +137,8 @@ namespace teachos::vga::x86_64::text } private: + using glyph = std::pair; + /** * @brief Move the cursor to a new line, scrolling the buffer if necessary. */ @@ -150,6 +155,8 @@ namespace teachos::vga::x86_64::text */ 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. * @@ -160,6 +167,10 @@ namespace teachos::vga::x86_64::text * @see vga::text::attribute */ auto writeln(std::string_view code_points, attribute attribute) -> void; + + std::span static const buffer; + + std::size_t m_position{}; }; } // namespace teachos::vga::x86_64::text diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index c5df5db..636e4cd 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -1,3 +1,16 @@ +.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 + .section .boot_text, "ax", @progbits .code64 @@ -10,6 +23,12 @@ _entry64: mov %rax, %fs mov %rax, %gs + mov multiboot_information_pointer, %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 diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 5142a2a..3848fb8 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -24,7 +24,7 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { - auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); + auto const & mbi = boot::bootstrap_information.mbi; return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), @@ -35,7 +35,7 @@ namespace teachos::memory auto create_early_frame_allocator() { - auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); + 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."); diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 6ecffa3..8b7f01b 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,38 +1,41 @@ #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 #include #include +#include #include #include namespace teachos::vga::x86_64::text { - using boot::x86_64::vga_buffer_pointer; - namespace { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit buffer_offset = std::ptrdiff_t{}; - + 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; - - auto write_char(char code_point, attribute attribute) -> void - { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; - }; } // namespace + std::span const device::buffer = + std::span{std::bit_cast(BUFFER_BASE_ADDRESS + + std::bit_cast(&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 { - buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT, - std::pair{' ', std::bit_cast(attribute)}); + m_position = 0; + std::ranges::fill(buffer, std::pair{' ', std::bit_cast(attribute)}); } auto device::cursor(bool enabled) -> void @@ -45,30 +48,35 @@ namespace teachos::vga::x86_64::text auto device::newline() -> void { - auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; + 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 = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; - auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; - std::ranges::move(begin, end, vga_buffer_pointer.get()); - buffer_offset = current_line * DEFAULT_TEXT_BUFFER_WIDTH; + 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 { - buffer_offset = next_line * DEFAULT_TEXT_BUFFER_WIDTH; + 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_char(code_point, attribute); }); + 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(attribute)}; + }; + auto device::writeln(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); newline(); } diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index 86b0fb6..553b9ba 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -5,6 +5,7 @@ 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/system.hpp" diff --git a/kapi/include/kapi/boot.hpp b/kapi/include/kapi/boot.hpp new file mode 100644 index 0000000..013e180 --- /dev/null +++ b/kapi/include/kapi/boot.hpp @@ -0,0 +1,11 @@ +#ifndef TEACHOS_KAPI_BOOT_HPP +#define TEACHOS_KAPI_BOOT_HPP + +namespace teachos::boot +{ + struct information; + + extern "C" information const bootstrap_information; +} // namespace teachos::boot + +#endif -- cgit v1.2.3 From 75dccce516db9ee4a43108015f78a9e99b21144f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 16:59:33 +0100 Subject: build: enable header verification --- CMakePresets.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 8943a4d..3e8a3a8 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,7 +8,8 @@ "toolchainFile": "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 } } ], -- cgit v1.2.3 From 1db039ca1c67e8daba8b5ec6d5158cb2110e1410 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Nov 2025 16:06:15 +0100 Subject: x86_64: port basic page and page table abstractions --- arch/x86_64/CMakeLists.txt | 4 + arch/x86_64/include/x86_64/memory/page_table.hpp | 139 ++++++++++++++++++++++ arch/x86_64/include/x86_64/memory/paging_root.hpp | 27 +++++ arch/x86_64/src/kapi/memory.cpp | 10 +- arch/x86_64/src/memory/page_table.cpp | 57 +++++++++ arch/x86_64/src/memory/paging_root.cpp | 19 +++ kapi/CMakeLists.txt | 4 + kapi/include/kapi/memory.hpp | 1 + kapi/include/kapi/memory/page.hpp | 59 +++++++++ 9 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 arch/x86_64/include/x86_64/memory/page_table.hpp create mode 100644 arch/x86_64/include/x86_64/memory/paging_root.hpp create mode 100644 arch/x86_64/src/memory/page_table.cpp create mode 100644 arch/x86_64/src/memory/paging_root.cpp create mode 100644 kapi/include/kapi/memory/page.hpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index cf85b36..8451945 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -24,6 +24,8 @@ target_sources("x86_64" PRIVATE # Memory management "src/memory/mmu.cpp" + "src/memory/page_table.cpp" + "src/memory/paging_root.cpp" "src/memory/region_allocator.cpp" # VGA text mode @@ -48,6 +50,8 @@ target_sources("x86_64" PRIVATE # Memory management "include/x86_64/memory/mmu.hpp" + "include/x86_64/memory/page_table.hpp" + "include/x86_64/memory/paging_root.hpp" "include/x86_64/memory/region_allocator.hpp" # VGA I/O 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..53af5d0 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -0,0 +1,139 @@ +#ifndef TEACHOS_X86_64_PAGE_TABLE_HPP +#define TEACHOS_X86_64_PAGE_TABLE_HPP + +#include "kapi/memory.hpp" + +#include +#include +#include +#include +#include +#include + +namespace teachos::memory::x86_64 +{ + + //! A table containing paging entries. + struct page_table + { + //! The maximum number of entries in this table. + constexpr auto static entry_count{512}; + + //! A single page table entry + struct entry + { + //! Flags marking the state and configuration of an entry. + enum struct flags : std::uint64_t + { + empty = 0, + present = 1uz << 0, + writable = 1uz << 1, + user_accessible = 1uz << 2, + write_through = 1uz << 3, + disable_cache = 1uz << 4, + accessed = 1uz << 5, + dirty = 1uz << 6, + huge_page = 1uz << 7, + global = 1uz << 8, + no_execute = 1uz << 63, + }; + + entry() = default; + + //! Clear this entry, ensuring all information is set to zero, marking the page represented by this entry as not + //! present. + auto clear() -> void; + + //! Check if the page represented by this entry is present at the containing page table's level. + [[nodiscard]] auto present() const -> bool; + + //! Check if the page represented by this entry is huge (2MiB, or 1GiB, depending on the containing page table's + //! level). + [[nodiscard]] auto huge() const -> bool; + + //! Get all flags present in this entry. + [[nodiscard]] auto all_flags() const -> flags; + + //! Get the frame number associated with this entry, if the referenced page is present. + [[nodiscard]] auto frame() const -> std::optional; + + //! Set the entry to reference the given frame with the given flags. + auto frame(struct frame frame, flags flags) -> void; + + private: + //! A mask to retrieve, or exclude, the frame number from the raw entry. + constexpr auto static frame_number_mask{0x000f'ffff'ffff'f000uz}; + + std::uint64_t m_raw{}; + }; + + //! Get the entry at the given index. + [[nodiscard]] auto operator[](std::size_t index) -> entry &; + [[nodiscard]] auto operator[](std::size_t index) const -> entry const &; + + //! Clear the entire page table, effectively evicting all entries. + auto clear() -> void; + + private: + std::array m_entries{}; + }; + + constexpr auto operator|(page_table::entry::flags lhs, page_table::entry::flags rhs) -> page_table::entry::flags + { + return std::bit_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); + } + + constexpr auto operator&(page_table::entry::flags lhs, page_table::entry::flags rhs) -> page_table::entry::flags + { + return std::bit_cast(std::to_underlying(lhs) & std::to_underlying(rhs)); + } + + //! A recursively mapped page table. + template + 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. + [[nodiscard]] auto next(this auto && self, std::size_t index) + requires(next_level > 1) + { + return self.next_address(index).transform([](auto address) -> auto { + auto table_pointer = std::bit_cast *>(address); + return &std::forward_like(*table_pointer); + }); + } + + //! Get the next lower lever table. + [[nodiscard]] auto next(this auto && self, std::size_t index) + requires(next_level == 1) + { + return self.next_address(index).transform([](auto address) -> auto { + auto table_pointer = std::bit_cast(address); + return &std::forward_like(*table_pointer); + }); + } + + private: + constexpr auto static level_bits = 9; + constexpr auto static high_bit = 48; + constexpr auto static offset_bits = 12; + + [[nodiscard]] auto next_address(std::size_t index) const -> std::optional + { + if (auto entry = (*this)[index]; entry.present() && !entry.huge()) + { + auto this_address = std::bit_cast(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 + +#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..365e180 --- /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 "kapi/memory.hpp" + +#include "x86_64/memory/page_table.hpp" + +#include + +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 &; + + [[nodiscard]] auto translate(linear_address address) const -> std::optional; + [[nodiscard]] auto translate(page page) const -> std::optional; + + private: + paging_root() = default; + }; + +} // namespace teachos::memory::x86_64 + +#endif \ No newline at end of file diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 3848fb8..99dcb5c 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -12,6 +12,7 @@ #include #include +#include namespace teachos::memory { @@ -25,11 +26,12 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::bootstrap_information.mbi; + auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; + auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; - return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, - physical_address{&boot::x86_64::_end_physical}), - .mbi_range = std::make_pair(physical_address{std::bit_cast(mbi)}, - physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), + return {.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 = mbi->memory_map()}; }; 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..c716c5c --- /dev/null +++ b/arch/x86_64/src/memory/page_table.cpp @@ -0,0 +1,57 @@ +#include "x86_64/memory/page_table.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + auto page_table::entry::clear() -> void + { + m_raw = 0; + } + + auto page_table::entry::present() const -> bool + { + return (flags() & flags::present) != flags::empty; + } + + auto page_table::entry::huge() const -> bool + { + return (flags() & flags::huge_page) != flags::empty; + } + + auto page_table::entry::all_flags() const -> flags + { + return std::bit_cast(m_raw & ~frame_number_mask); + } + + auto page_table::entry::frame() const -> std::optional + { + 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) -> void + { + m_raw = (frame.start_address().raw() | static_cast(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() -> void + { + std::ranges::for_each(m_entries, &page_table::entry::clear); + } + +} // namespace teachos::memory::x86_64 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..1234308 --- /dev/null +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -0,0 +1,19 @@ +#include "x86_64/memory/paging_root.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + namespace + { + constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; + } + + auto paging_root::get() -> paging_root & + { + auto pml4_address = std::bit_cast(PML_RECURSIVE_BASE); + return *pml4_address; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index 553b9ba..ca26615 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -8,6 +8,10 @@ target_sources("kapi" PUBLIC "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.hpp" "include/kapi/system.hpp" ) diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp index 3daaa86..4279274 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/include/kapi/memory.hpp @@ -4,6 +4,7 @@ #include "kapi/memory/address.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 namespace teachos::memory { diff --git a/kapi/include/kapi/memory/page.hpp b/kapi/include/kapi/memory/page.hpp new file mode 100644 index 0000000..2b8e52a --- /dev/null +++ b/kapi/include/kapi/memory/page.hpp @@ -0,0 +1,59 @@ +#ifndef TEACHOS_KAPI_MEMORY_PAGE_HPP +#define TEACHOS_KAPI_MEMORY_PAGE_HPP + +#include "kapi/memory/address.hpp" + +#include +#include + +namespace teachos::memory +{ + + extern std::size_t const PLATFORM_PAGE_SIZE; + + struct page + { + constexpr page() = default; + + explicit constexpr page(std::size_t number) + : m_number{number} + {} + + /** + * @brief Returns the virtual page the given address is contained in. + * + * @param address Linear address we want to get the corresponding virtual page for. + * @return Page the given address is contained in. + */ + constexpr auto static containing(linear_address address) noexcept -> page + { + return page{address.raw() / PLATFORM_PAGE_SIZE}; + } + + /** + * @brief Get the start address of this virtual page. + * + * @return Start address of the virtual page. + */ + [[nodiscard]] constexpr auto start_address() const noexcept -> linear_address + { + return linear_address{m_number * PLATFORM_PAGE_SIZE}; + } + + /** + * @brief Check if this page refers to the same page as @p other. + */ + constexpr auto operator==(page const & other) const noexcept -> bool = default; + + /** + * @brief Lexicographically compare this page to @p other. + */ + constexpr auto operator<=>(page const & other) const noexcept -> std::strong_ordering = default; + + private: + std::size_t m_number{}; + }; + +} // namespace teachos::memory + +#endif \ No newline at end of file -- cgit v1.2.3 From 57d140f41b462483b8f32a883cbb0b599b9feaed Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 30 Nov 2025 16:59:17 +0100 Subject: x86_64/memory: fix entry checks --- arch/x86_64/src/memory/page_table.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index c716c5c..1273676 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -12,12 +12,12 @@ namespace teachos::memory::x86_64 auto page_table::entry::present() const -> bool { - return (flags() & flags::present) != flags::empty; + return (all_flags() & flags::present) != flags::empty; } auto page_table::entry::huge() const -> bool { - return (flags() & flags::huge_page) != flags::empty; + return (all_flags() & flags::huge_page) != flags::empty; } auto page_table::entry::all_flags() const -> flags -- cgit v1.2.3 From cf833d0e8676f6a5ee6b536b4cb5202e9446ab87 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 15:55:52 +0100 Subject: x86_64/memory: prevent copying of page root --- arch/x86_64/include/x86_64/memory/paging_root.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86_64/include/x86_64/memory/paging_root.hpp b/arch/x86_64/include/x86_64/memory/paging_root.hpp index 365e180..e9b8eef 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -15,6 +15,11 @@ namespace teachos::memory::x86_64 { 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; + [[nodiscard]] auto translate(linear_address address) const -> std::optional; [[nodiscard]] auto translate(page page) const -> std::optional; -- cgit v1.2.3 From 27eddc3fa8d4c6001f223670d6001554fc47b657 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 15:56:58 +0100 Subject: x86_64/memory: implement PML4 injection --- arch/x86_64/src/kapi/memory.cpp | 74 ++++++++++++++++++++++++++++++++++-- kapi/include/kapi/memory/address.hpp | 11 ++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 99dcb5c..f34729a 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,28 +1,34 @@ #include "kapi/memory.hpp" -#include "kapi/memory/frame.hpp" -#include "kapi/memory/frame_allocator.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/mmu.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" #include "x86_64/memory/region_allocator.hpp" #include #include +#include #include namespace teachos::memory { std::size_t const PLATFORM_FRAME_SIZE{4096}; + std::size_t const PLATFORM_PAGE_SIZE{PLATFORM_FRAME_SIZE}; namespace { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); + constexpr auto static unused_page_address = 0x0000'7fff'cafe'faceuz; + auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::bootstrap_information.mbi; @@ -51,6 +57,67 @@ namespace teachos::memory 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); } + + auto inject_faux_pml4(frame_allocator & allocator) -> void + { + using entry_flags = x86_64::page_table::entry::flags; + using page_table = x86_64::page_table; + + auto temporary_page = page::containing(linear_address{unused_page_address}); + auto temporary_page_address = temporary_page.start_address(); + + auto & pml4 = x86_64::paging_root::get(); + + // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) + auto faux_pml4_frame = + allocator.allocate() + .and_then([&](auto frame) -> auto { + auto index = temporary_page_address >> 39 & 0x1ffu; + pml4[index].frame(frame, entry_flags::present | entry_flags::writable); + return pml4.next(index); + }) + .and_then([&](auto pml) -> auto { + std::construct_at(pml); + auto index = temporary_page_address >> 30 & 0x1ffu; + (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); + return pml->next(index); + }) + .and_then([&](auto pml) -> auto { + std::construct_at(pml); + auto index = temporary_page_address >> 21 & 0x1ffu; + (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); + return pml->next(index); + }) + .transform([&](auto pml) -> auto { + std::construct_at(pml); + auto index = temporary_page_address >> 12 & 0x1ffu; + (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); + return pml; + }) + .and_then([&](auto pml) -> auto { + auto faux_pml4_pointer = std::bit_cast(temporary_page_address.raw()); + auto faux_pml4 = std::construct_at(faux_pml4_pointer); + + auto index = temporary_page_address >> 12 & 0x1ffu; + auto frame = (*pml)[index].frame(); + + (*faux_pml4)[510].frame(*frame, entry_flags::present | entry_flags::writable); + return frame; + }); + // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) + + if (!faux_pml4_frame) + { + system::panic("[MEM] Failed to map and construct faux PML4"); + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + pml4[510].frame(*faux_pml4_frame, entry_flags::present | entry_flags::writable); + x86_64::tlb_flush_all(); + + cio::println("[MEM] Injected faux PML4 as recursive map."); + } + } // namespace auto active_allocator() -> frame_allocator & @@ -71,8 +138,9 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - [[maybe_unused]] auto allocator = create_early_frame_allocator(); + auto allocator = create_early_frame_allocator(); enable_cpu_protections(); + inject_faux_pml4(allocator); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp index 19615e4..ad82f20 100644 --- a/kapi/include/kapi/memory/address.hpp +++ b/kapi/include/kapi/memory/address.hpp @@ -33,6 +33,17 @@ namespace teachos::memory return std::bit_cast(m_value); } + constexpr auto operator>>(std::size_t n) const noexcept -> address + { + return address{m_value >> n}; + } + + template + constexpr auto operator&(MaskType mask) const noexcept -> MaskType + { + return static_cast(m_value & mask); + } + constexpr auto operator<=>(address const &) const noexcept -> std::strong_ordering = default; constexpr auto operator==(address const &) const noexcept -> bool = default; -- cgit v1.2.3 From 005d7ea3df29e736750d409b816caa29cf9bab2f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 16:04:27 +0100 Subject: kapi: mark memory sub-headers private --- kapi/include/kapi/memory/address.hpp | 2 ++ kapi/include/kapi/memory/frame.hpp | 2 ++ kapi/include/kapi/memory/frame_allocator.hpp | 2 ++ kapi/include/kapi/memory/page.hpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp index ad82f20..b861ef5 100644 --- a/kapi/include/kapi/memory/address.hpp +++ b/kapi/include/kapi/memory/address.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_KAPI_MEMORY_ADDRESS_HPP #define TEACHOS_KAPI_MEMORY_ADDRESS_HPP +// IWYU pragma: private, include "kapi/memory.hpp" + #include #include #include diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp index 63b1e70..095a3df 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/include/kapi/memory/frame.hpp @@ -1,6 +1,8 @@ #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 diff --git a/kapi/include/kapi/memory/frame_allocator.hpp b/kapi/include/kapi/memory/frame_allocator.hpp index 22102a6..6206860 100644 --- a/kapi/include/kapi/memory/frame_allocator.hpp +++ b/kapi/include/kapi/memory/frame_allocator.hpp @@ -1,6 +1,8 @@ #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 diff --git a/kapi/include/kapi/memory/page.hpp b/kapi/include/kapi/memory/page.hpp index 2b8e52a..b84094f 100644 --- a/kapi/include/kapi/memory/page.hpp +++ b/kapi/include/kapi/memory/page.hpp @@ -1,6 +1,8 @@ #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 -- cgit v1.2.3 From 203355e51690073e571d4906d53f2494c3dad41b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 19:32:19 +0100 Subject: x86_64/memory: prepare scoped_mapping extraction --- arch/x86_64/CMakeLists.txt | 2 + .../include/x86_64/memory/scoped_mapping.hpp | 39 ++++++++++++ arch/x86_64/src/kapi/memory.cpp | 12 ++++ arch/x86_64/src/memory/scoped_mapping.cpp | 73 ++++++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 arch/x86_64/include/x86_64/memory/scoped_mapping.hpp create mode 100644 arch/x86_64/src/memory/scoped_mapping.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8451945..4d32f76 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -27,6 +27,7 @@ target_sources("x86_64" PRIVATE "src/memory/page_table.cpp" "src/memory/paging_root.cpp" "src/memory/region_allocator.cpp" + "src/memory/scoped_mapping.cpp" # VGA text mode "src/vga/text.cpp" @@ -53,6 +54,7 @@ target_sources("x86_64" PRIVATE "include/x86_64/memory/page_table.hpp" "include/x86_64/memory/paging_root.hpp" "include/x86_64/memory/region_allocator.hpp" + "include/x86_64/memory/scoped_mapping.hpp" # VGA I/O "include/x86_64/vga/text.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..1719e6b --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -0,0 +1,39 @@ +#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 +{ + + struct scoped_mapping + { + scoped_mapping(scoped_mapping const &) = delete; + scoped_mapping(scoped_mapping &&); + scoped_mapping(linear_address address, frame_allocator & allocator); + + ~scoped_mapping(); + + auto operator=(scoped_mapping const &) -> scoped_mapping = delete; + auto operator=(scoped_mapping &&) -> scoped_mapping &; + + auto map(frame frame, page_table::entry::flags flags) -> std::byte *; + auto unmap() -> void; + + template + auto map_as(frame frame, page_table::entry::flags flags) -> DataType * + { + return std::bit_cast(map(frame, flags)); + } + + private: + linear_address m_address; + frame_allocator * m_allocator; + bool m_mapped; + }; + +} // namespace teachos::memory::x86_64 + +#endif \ No newline at end of file diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index f34729a..920c82b 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -10,6 +10,7 @@ #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/paging_root.hpp" #include "x86_64/memory/region_allocator.hpp" +#include "x86_64/memory/scoped_mapping.hpp" #include @@ -140,8 +141,19 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); + + // TODO: remove inject_faux_pml4(allocator); + // TODO: implement + auto temporary_mapper = x86_64::scoped_mapping{linear_address{unused_page_address}, allocator}; + auto new_pml4_frame = allocator.allocate(); + + auto new_plm4 = temporary_mapper.map_as( + *new_pml4_frame, x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); + (*new_plm4)[510].frame(new_pml4_frame.value(), + x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); + // 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); 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..c436ee5 --- /dev/null +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -0,0 +1,73 @@ +#include "x86_64/memory/scoped_mapping.hpp" + +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include "x86_64/memory/mmu.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + scoped_mapping::scoped_mapping(scoped_mapping && other) + : m_address{std::exchange(other.m_address, linear_address{})} + , m_allocator{std::exchange(other.m_allocator, nullptr)} + , m_mapped{std::exchange(other.m_mapped, false)} + {} + + scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) + : m_address{address} + , m_allocator{&allocator} + , m_mapped{false} + {} + + scoped_mapping::~scoped_mapping() + { + if (m_mapped) + { + unmap(); + x86_64::tlb_flush(m_address); + } + } + + auto scoped_mapping::operator=(scoped_mapping && other) -> scoped_mapping & + { + if (&other == this) + { + return *this; + } + + using std::swap; + + swap(m_address, other.m_address); + swap(m_allocator, other.m_allocator); + swap(m_mapped, other.m_mapped); + + return *this; + } + + auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * + { + static_cast(frame); + static_cast(flags); + + m_mapped = true; + + return nullptr; + } + + auto scoped_mapping::unmap() -> void + { + if (!m_mapped) + { + system::panic("[MEM] Tried to release an unmapped temporary mapping!"); + } + + // TODO: scan pages + // TODO: remove mapping + // TODO: release temporary table frames + m_mapped = false; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From be86be1facfce8fe3f376153b9c582f2c5c026aa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 12:31:53 +0100 Subject: x86_64/memory: extend scoped_mapping --- arch/x86_64/CMakeLists.txt | 1 + .../include/x86_64/memory/page_utilities.hpp | 22 ++++++++++++ arch/x86_64/src/memory/paging_root.cpp | 41 ++++++++++++++++++++++ arch/x86_64/src/memory/scoped_mapping.cpp | 8 ++++- kapi/include/kapi/memory/frame.hpp | 5 +++ kapi/include/kapi/memory/page.hpp | 5 +++ 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/include/x86_64/memory/page_utilities.hpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4d32f76..f010dcf 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,6 +52,7 @@ target_sources("x86_64" PRIVATE # Memory management "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/region_allocator.hpp" "include/x86_64/memory/scoped_mapping.hpp" 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 + +namespace teachos::memory::x86_64 +{ + + template + 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/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 1234308..6b65f60 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,6 +1,11 @@ #include "x86_64/memory/paging_root.hpp" +#include "kapi/memory.hpp" + +#include "x86_64/memory/page_utilities.hpp" + #include +#include namespace teachos::memory::x86_64 { @@ -16,4 +21,40 @@ namespace teachos::memory::x86_64 return *pml4_address; } + auto paging_root::translate(linear_address address) const -> std::optional + { + auto offset = address.raw() % PLATFORM_PAGE_SIZE; + return translate(page::containing(address)).transform([offset](auto frame) -> auto { + return physical_address{frame.start_address().raw() + offset}; + }); + } + + auto paging_root::translate(page page) const -> std::optional + { + auto pml3 = next(pml_index<4>(page)); + + if (!pml3) + { + return std::nullopt; + } + + auto handle_huge_page = [&] -> std::optional { + auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); + if (pml3_entry && 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 pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + + 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); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index c436ee5..27c4785 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,6 +4,7 @@ #include "kapi/system.hpp" #include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/paging_root.hpp" #include @@ -20,7 +21,12 @@ namespace teachos::memory::x86_64 : m_address{address} , m_allocator{&allocator} , m_mapped{false} - {} + { + if (paging_root::get().translate(address)) + { + system::panic("[MEM] Tried to map a page that is already mapped!"); + } + } scoped_mapping::~scoped_mapping() { diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp index 095a3df..5793b8b 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/include/kapi/memory/frame.hpp @@ -42,6 +42,11 @@ namespace teachos::memory return physical_address{m_number * PLATFORM_FRAME_SIZE}; } + [[nodiscard]] constexpr auto number() const noexcept -> std::size_t + { + return m_number; + } + /** * @brief Get the nth next frame. * diff --git a/kapi/include/kapi/memory/page.hpp b/kapi/include/kapi/memory/page.hpp index b84094f..473a8b8 100644 --- a/kapi/include/kapi/memory/page.hpp +++ b/kapi/include/kapi/memory/page.hpp @@ -42,6 +42,11 @@ namespace teachos::memory return linear_address{m_number * PLATFORM_PAGE_SIZE}; } + [[nodiscard]] constexpr auto number() const noexcept -> std::size_t + { + return m_number; + } + /** * @brief Check if this page refers to the same page as @p other. */ -- cgit v1.2.3 From a96b1b4b43a1ed962b412c3d28db0fe00661d96f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:40:10 +0100 Subject: x86_64/memory: extract PML4 injection --- arch/x86_64/include/x86_64/memory/page_table.hpp | 3 + .../include/x86_64/memory/scoped_mapping.hpp | 4 +- arch/x86_64/src/kapi/memory.cpp | 79 ++++------------------ arch/x86_64/src/memory/page_table.cpp | 6 ++ arch/x86_64/src/memory/paging_root.cpp | 18 ++++- arch/x86_64/src/memory/scoped_mapping.cpp | 77 +++++++++++++++++---- 6 files changed, 103 insertions(+), 84 deletions(-) diff --git a/arch/x86_64/include/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp index 53af5d0..6b8eb8c 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -74,6 +74,9 @@ namespace teachos::memory::x86_64 //! Clear the entire page table, effectively evicting all entries. auto clear() -> void; + //! Check if the page table is empty. + [[nodiscard]] auto empty() const noexcept -> bool; + private: std::array m_entries{}; }; diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index 1719e6b..5737bb0 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -12,7 +12,7 @@ namespace teachos::memory::x86_64 { scoped_mapping(scoped_mapping const &) = delete; scoped_mapping(scoped_mapping &&); - scoped_mapping(linear_address address, frame_allocator & allocator); + scoped_mapping(page page, frame_allocator & allocator); ~scoped_mapping(); @@ -29,7 +29,7 @@ namespace teachos::memory::x86_64 } private: - linear_address m_address; + page m_page; frame_allocator * m_allocator; bool m_mapped; }; diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 920c82b..36b1706 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,6 +1,5 @@ #include "kapi/memory.hpp" -#include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" @@ -28,7 +27,8 @@ namespace teachos::memory // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); - constexpr auto static unused_page_address = 0x0000'7fff'cafe'faceuz; + constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; + constexpr auto static recursive_page_map_index = 510; auto create_memory_information() -> x86_64::region_allocator::memory_information { @@ -61,62 +61,18 @@ namespace teachos::memory auto inject_faux_pml4(frame_allocator & allocator) -> void { - using entry_flags = x86_64::page_table::entry::flags; - using page_table = x86_64::page_table; - - auto temporary_page = page::containing(linear_address{unused_page_address}); - auto temporary_page_address = temporary_page.start_address(); - - auto & pml4 = x86_64::paging_root::get(); - - // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) - auto faux_pml4_frame = - allocator.allocate() - .and_then([&](auto frame) -> auto { - auto index = temporary_page_address >> 39 & 0x1ffu; - pml4[index].frame(frame, entry_flags::present | entry_flags::writable); - return pml4.next(index); - }) - .and_then([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 30 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml->next(index); - }) - .and_then([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 21 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml->next(index); - }) - .transform([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 12 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml; - }) - .and_then([&](auto pml) -> auto { - auto faux_pml4_pointer = std::bit_cast(temporary_page_address.raw()); - auto faux_pml4 = std::construct_at(faux_pml4_pointer); - - auto index = temporary_page_address >> 12 & 0x1ffu; - auto frame = (*pml)[index].frame(); - - (*faux_pml4)[510].frame(*frame, entry_flags::present | entry_flags::writable); - return frame; - }); - // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) - - if (!faux_pml4_frame) - { - system::panic("[MEM] Failed to map and construct faux PML4"); - } + using namespace x86_64; + using entry_flags = page_table::entry::flags; + + auto temporary_mapper = scoped_mapping{page::containing(unused_page_address), allocator}; + auto new_pml4_frame = allocator.allocate(); - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) - pml4[510].frame(*faux_pml4_frame, entry_flags::present | entry_flags::writable); - x86_64::tlb_flush_all(); + auto pml4 = std::construct_at(temporary_mapper.map_as(*new_pml4_frame, entry_flags::writable)); + (*pml4)[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable); + paging_root::get()[recursive_page_map_index].frame(new_pml4_frame.value(), + entry_flags::present | entry_flags::writable); - cio::println("[MEM] Injected faux PML4 as recursive map."); + tlb_flush_all(); } } // namespace @@ -141,19 +97,8 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - - // TODO: remove inject_faux_pml4(allocator); - // TODO: implement - auto temporary_mapper = x86_64::scoped_mapping{linear_address{unused_page_address}, allocator}; - auto new_pml4_frame = allocator.allocate(); - - auto new_plm4 = temporary_mapper.map_as( - *new_pml4_frame, x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); - (*new_plm4)[510].frame(new_pml4_frame.value(), - x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); - // 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); diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 1273676..60bf94d 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -54,4 +54,10 @@ namespace teachos::memory::x86_64 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_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b65f60..a29304e 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -40,13 +40,27 @@ namespace teachos::memory::x86_64 auto handle_huge_page = [&] -> std::optional { auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (pml3_entry && pml3_entry->huge()) + 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 pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + 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; }; diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 27c4785..602198e 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,25 +4,28 @@ #include "kapi/system.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 #include namespace teachos::memory::x86_64 { scoped_mapping::scoped_mapping(scoped_mapping && other) - : m_address{std::exchange(other.m_address, linear_address{})} + : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} {} - scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) - : m_address{address} + scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + : m_page{page} , m_allocator{&allocator} , m_mapped{false} { - if (paging_root::get().translate(address)) + if (paging_root::get().translate(page)) { system::panic("[MEM] Tried to map a page that is already mapped!"); } @@ -33,7 +36,7 @@ namespace teachos::memory::x86_64 if (m_mapped) { unmap(); - x86_64::tlb_flush(m_address); + x86_64::tlb_flush(m_page.start_address()); } } @@ -46,7 +49,7 @@ namespace teachos::memory::x86_64 using std::swap; - swap(m_address, other.m_address); + swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); @@ -55,12 +58,38 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - static_cast(frame); - static_cast(flags); + auto & pml4 = paging_root::get(); + auto pml4_index = pml_index<4>(m_page); + if (!pml4[pml4_index].present()) + { + auto new_frame = m_allocator->allocate(); + pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at(pml4.next(pml4_index).value()); + } - m_mapped = true; + auto pml3 = pml4.next(pml4_index).value(); + auto pml3_index = pml_index<3>(m_page); + if (!(*pml3)[pml3_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml3).next(pml3_index).value()); + } - return nullptr; + auto pml2 = (*pml3).next(pml3_index).value(); + auto pml2_index = pml_index<2>(m_page); + if (!(*pml2)[pml2_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml2).next(pml2_index).value()); + } + + auto pml1 = (*pml2).next(pml2_index).value(); + auto pml1_index = pml_index<1>(m_page); + (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + + return static_cast(frame.start_address()); } auto scoped_mapping::unmap() -> void @@ -70,9 +99,31 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - // TODO: scan pages - // TODO: remove mapping - // TODO: release temporary table frames + auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml2 = pml3->next(pml_index<3>(m_page)).value(); + auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } + + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } + + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } + m_mapped = false; } -- cgit v1.2.3 From 44d4844ce63e7c00b4028bb918eed5d9fb795578 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:43:29 +0100 Subject: x86_64/build: automatically collect headers --- arch/x86_64/CMakeLists.txt | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index f010dcf..9afbce3 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -33,32 +33,12 @@ target_sources("x86_64" PRIVATE "src/vga/text.cpp" ) +file(GLOB_RECURSE ARCH_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") + target_sources("x86_64" PRIVATE FILE_SET HEADERS BASE_DIRS "include" - FILES - # Low-level bootstrap - "include/x86_64/boot/boot.hpp" - "include/x86_64/boot/ld.hpp" - - # Low-level CPU access - "include/x86_64/cpu/registers.hpp" - "include/x86_64/cpu/impl/control_registers.hpp" - "include/x86_64/cpu/impl/model_specific_register.hpp" - - # Low-level device I/O - "include/x86_64/device_io/port_io.hpp" - - # Memory management - "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/region_allocator.hpp" - "include/x86_64/memory/scoped_mapping.hpp" - - # VGA I/O - "include/x86_64/vga/text.hpp" + FILES ${ARCH_HEADERS} ) set(KERNEL_LINKER_SCRIPT -- cgit v1.2.3 From 331c070547634a2096c5e2165559fb0f11ee6330 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:49:36 +0100 Subject: kapi: make PLATFORM_*_SIZE constexpr --- arch/x86_64/CMakeLists.txt | 7 ++++++- arch/x86_64/src/kapi/memory.cpp | 2 -- arch/x86_64/src/memory/paging_root.cpp | 2 +- kapi/include/kapi/memory/frame.hpp | 8 ++++---- kapi/include/kapi/memory/page.hpp | 8 ++++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9afbce3..4d984cf 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -41,7 +41,12 @@ target_sources("x86_64" PRIVATE FILES ${ARCH_HEADERS} ) +target_compile_definitions("x86_64" PUBLIC + "PLATFORM_PAGE_SIZE=4096" + "PLATFORM_FRAME_SIZE=PLATFORM_PAGE_SIZE" +) + set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" PARENT_SCOPE -) \ No newline at end of file +) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 36b1706..1a8b36f 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -19,8 +19,6 @@ namespace teachos::memory { - std::size_t const PLATFORM_FRAME_SIZE{4096}; - std::size_t const PLATFORM_PAGE_SIZE{PLATFORM_FRAME_SIZE}; namespace { diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index a29304e..6b8e1ab 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -23,7 +23,7 @@ namespace teachos::memory::x86_64 auto paging_root::translate(linear_address address) const -> std::optional { - auto offset = address.raw() % PLATFORM_PAGE_SIZE; + auto offset = address.raw() % page::size; return translate(page::containing(address)).transform([offset](auto frame) -> auto { return physical_address{frame.start_address().raw() + offset}; }); diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp index 5793b8b..10e4172 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/include/kapi/memory/frame.hpp @@ -11,10 +11,10 @@ namespace teachos::memory { - extern std::size_t const PLATFORM_FRAME_SIZE; - struct frame { + constexpr auto static size = PLATFORM_FRAME_SIZE; + constexpr frame() = default; explicit constexpr frame(std::size_t number) @@ -29,7 +29,7 @@ namespace teachos::memory */ constexpr auto static containing(physical_address address) noexcept -> frame { - return frame{address.raw() / PLATFORM_FRAME_SIZE}; + return frame{address.raw() / size}; } /** @@ -39,7 +39,7 @@ namespace teachos::memory */ [[nodiscard]] constexpr auto start_address() const noexcept -> physical_address { - return physical_address{m_number * PLATFORM_FRAME_SIZE}; + return physical_address{m_number * size}; } [[nodiscard]] constexpr auto number() const noexcept -> std::size_t diff --git a/kapi/include/kapi/memory/page.hpp b/kapi/include/kapi/memory/page.hpp index 473a8b8..9bb22e9 100644 --- a/kapi/include/kapi/memory/page.hpp +++ b/kapi/include/kapi/memory/page.hpp @@ -11,10 +11,10 @@ namespace teachos::memory { - extern std::size_t const PLATFORM_PAGE_SIZE; - struct page { + constexpr auto static size = PLATFORM_FRAME_SIZE; + constexpr page() = default; explicit constexpr page(std::size_t number) @@ -29,7 +29,7 @@ namespace teachos::memory */ constexpr auto static containing(linear_address address) noexcept -> page { - return page{address.raw() / PLATFORM_PAGE_SIZE}; + return page{address.raw() / size}; } /** @@ -39,7 +39,7 @@ namespace teachos::memory */ [[nodiscard]] constexpr auto start_address() const noexcept -> linear_address { - return linear_address{m_number * PLATFORM_PAGE_SIZE}; + return linear_address{m_number * size}; } [[nodiscard]] constexpr auto number() const noexcept -> std::size_t -- cgit v1.2.3 From 588fe1a3600475bdc312a4fe758d2f1125eb149c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:56:12 +0100 Subject: x86_64: basic code cleanup --- arch/x86_64/include/x86_64/memory/page_table.hpp | 6 +++--- arch/x86_64/include/x86_64/memory/paging_root.hpp | 2 ++ arch/x86_64/src/kapi/memory.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp index 6b8eb8c..c5102a2 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -16,9 +16,6 @@ namespace teachos::memory::x86_64 //! A table containing paging entries. struct page_table { - //! The maximum number of entries in this table. - constexpr auto static entry_count{512}; - //! A single page table entry struct entry { @@ -67,6 +64,9 @@ namespace teachos::memory::x86_64 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. [[nodiscard]] auto operator[](std::size_t index) -> entry &; [[nodiscard]] auto operator[](std::size_t index) const -> entry const &; diff --git a/arch/x86_64/include/x86_64/memory/paging_root.hpp b/arch/x86_64/include/x86_64/memory/paging_root.hpp index e9b8eef..a9ab6a6 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -20,6 +20,8 @@ namespace teachos::memory::x86_64 auto operator=(paging_root const &) -> paging_root & = delete; auto operator=(paging_root &&) -> paging_root & = delete; + ~paging_root() = delete; + [[nodiscard]] auto translate(linear_address address) const -> std::optional; [[nodiscard]] auto translate(page page) const -> std::optional; diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 1a8b36f..e138641 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -26,7 +26,7 @@ namespace teachos::memory auto constinit allocator = static_cast(nullptr); constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; - constexpr auto static recursive_page_map_index = 510; + constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; auto create_memory_information() -> x86_64::region_allocator::memory_information { -- cgit v1.2.3 From 148c54a3d470c6019ebebe1387a7d889a2b8808e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 19:17:42 +0100 Subject: x86_64/memory: introduce frame allocation buffer --- arch/x86_64/CMakeLists.txt | 2 +- .../include/x86_64/memory/buffered_allocator.hpp | 67 ++++++++++++++++++++++ arch/x86_64/src/kapi/memory.cpp | 5 +- 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 arch/x86_64/include/x86_64/memory/buffered_allocator.hpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4d984cf..7f01744 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -35,7 +35,7 @@ target_sources("x86_64" PRIVATE file(GLOB_RECURSE ARCH_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") -target_sources("x86_64" PRIVATE +target_sources("x86_64" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES ${ARCH_HEADERS} 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..2d05010 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp @@ -0,0 +1,67 @@ +#ifndef TEACHOS_X86_64_BUFFERED_ALLOCATOR_HPP +#define TEACHOS_X86_64_BUFFERED_ALLOCATOR_HPP + +#include "kapi/memory.hpp" + +#include +#include +#include + +namespace teachos::memory::x86_64 +{ + + template + 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 &&) = default; + + ~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() -> std::optional 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, BufferSize> m_pool{}; + }; + +} // namespace teachos::memory::x86_64 + +#endif \ No newline at end of file diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index e138641..703b3e1 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -5,6 +5,7 @@ #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/mmu.hpp" #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/paging_root.hpp" @@ -95,7 +96,9 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - inject_faux_pml4(allocator); + + auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; + inject_faux_pml4(allocation_buffer); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From 9331afdcbbe95bc1bd79d657f0d7c5b91a19a375 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 19:39:03 +0100 Subject: x86_64/memory: fix temporary page unmapping --- arch/x86_64/src/kapi/memory.cpp | 34 ++++++++++++++++++++++++++++++- arch/x86_64/src/memory/scoped_mapping.cpp | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 703b3e1..0e4b78e 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -8,6 +8,7 @@ #include "x86_64/memory/buffered_allocator.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/region_allocator.hpp" #include "x86_64/memory/scoped_mapping.hpp" @@ -63,15 +64,46 @@ namespace teachos::memory using namespace x86_64; using entry_flags = page_table::entry::flags; - auto temporary_mapper = scoped_mapping{page::containing(unused_page_address), allocator}; + auto page = page::containing(unused_page_address); + + auto temporary_mapper = scoped_mapping{page, allocator}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as(*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; } } // namespace diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 602198e..191a7ad 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -89,6 +89,8 @@ namespace teachos::memory::x86_64 auto pml1_index = pml_index<1>(m_page); (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + m_mapped = true; + return static_cast(frame.start_address()); } -- cgit v1.2.3 From a08847ded5fba25859e7a3ad06ae3fed342d4d6a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 14:02:07 +0100 Subject: x86_64/boot: move stack to higher half --- arch/x86_64/src/boot/boot32.S | 11 ++++------- arch/x86_64/src/boot/entry64.s | 9 +++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 27eed4d..79b3ec7 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -27,12 +27,9 @@ page_maps_size = page_maps_end - page_maps_start .section .boot_stack, "aw", @nobits .align 16 -.global stack_size -.global stack_bottom - -stack_bottom: .skip 1 << 20 -stack_top: -stack_size = stack_top - stack_bottom +early_stack_bottom: .skip 1 << 8 +early_stack_top: +early_stack_size = early_stack_top - early_stack_bottom /** * @brief Constants for the bootstrapping process. @@ -122,7 +119,7 @@ _start: 0: pop %esi - lea (stack_top - 0b)(%esi), %ecx + lea (early_stack_top - 0b)(%esi), %ecx mov %ecx, %esp mov %esp, %ebp diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index 636e4cd..2932354 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -11,6 +11,12 @@ .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 @@ -23,6 +29,9 @@ _entry64: mov %rax, %fs mov %rax, %gs + mov $stack_top, %rsp + mov %rsp, %rbp + mov multiboot_information_pointer, %rax mov vga_buffer_pointer, %rdx sub $0xb8000, %rdx -- cgit v1.2.3 From 9907cb6c0108b89b846fee52de56a9c335caaedc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 17:08:44 +0100 Subject: x86_64/memory: fix return in scoped_mapping::map Previously, scoped_mapping::map returned the start address of the frame. Unfortunately, the initial mapping performed in the bootstrap code maps physical memory starting at 0x0000'0000'0000'0000, which means no fault was triggered. The map function now correctly return the start address of the scoped_mapping's page, which must alway work by definition. --- arch/x86_64/src/memory/scoped_mapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 191a7ad..5446b2a 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -91,7 +91,7 @@ namespace teachos::memory::x86_64 m_mapped = true; - return static_cast(frame.start_address()); + return static_cast(m_page.start_address()); } auto scoped_mapping::unmap() -> void -- cgit v1.2.3 From d74936964ecd5e5c961b90feb9323ca999ce9026 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 17:23:12 +0100 Subject: x86_64/memory: improve scoped_mapping docs --- .../include/x86_64/memory/scoped_mapping.hpp | 35 ++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index 5737bb0..dff54ec 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -8,26 +8,51 @@ 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 { - scoped_mapping(scoped_mapping const &) = delete; - scoped_mapping(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 allocator An allocator to be used to allocate any page maps required to map the frame. scoped_mapping(page page, frame_allocator & allocator); - ~scoped_mapping(); + //! 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; - auto operator=(scoped_mapping &&) -> scoped_mapping &; + //! 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 *; - auto unmap() -> void; + //! Map the given frame, returning a typed pointer. template auto map_as(frame frame, page_table::entry::flags flags) -> DataType * { return std::bit_cast(map(frame, flags)); } + //! Unmap the mapped frame. + //! @note If no frame was ever mapped, this function will panic. + auto unmap() -> void; + private: page m_page; frame_allocator * m_allocator; -- cgit v1.2.3 From 448632c3c9c919e8eda44e8a83082f60983057b7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:16:36 +0100 Subject: x86_64/memory: add missing noexcept specifiers --- arch/x86_64/src/memory/scoped_mapping.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 5446b2a..6e2328d 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -14,7 +14,7 @@ namespace teachos::memory::x86_64 { - scoped_mapping::scoped_mapping(scoped_mapping && other) + scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} @@ -40,7 +40,7 @@ namespace teachos::memory::x86_64 } } - auto scoped_mapping::operator=(scoped_mapping && other) -> scoped_mapping & + auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { if (&other == this) { -- cgit v1.2.3 From f3dd2b2f5bd1b5dd4d4309a30db3c7733b8f63bb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:40:54 +0100 Subject: x86_64/memory: only deallocate allocated frames --- .../include/x86_64/memory/scoped_mapping.hpp | 1 + arch/x86_64/src/memory/scoped_mapping.cpp | 39 +++++++++++++++------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index dff54ec..99585bc 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -57,6 +57,7 @@ namespace teachos::memory::x86_64 page m_page; frame_allocator * m_allocator; bool m_mapped; + std::uint8_t m_allocated; }; } // 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 index 6e2328d..be15330 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -18,12 +18,14 @@ namespace teachos::memory::x86_64 : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} + , m_allocated{std::exchange(other.m_allocated, 0)} {} scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) : m_page{page} , m_allocator{&allocator} , m_mapped{false} + , m_allocated{} { if (paging_root::get().translate(page)) { @@ -52,6 +54,7 @@ namespace teachos::memory::x86_64 swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); + swap(m_allocated, other.m_allocated); return *this; } @@ -65,6 +68,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at(pml4.next(pml4_index).value()); + m_allocated |= 1uz << 2; } auto pml3 = pml4.next(pml4_index).value(); @@ -74,6 +78,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at((*pml3).next(pml3_index).value()); + m_allocated |= 1uz << 1; } auto pml2 = (*pml3).next(pml3_index).value(); @@ -83,6 +88,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at((*pml2).next(pml2_index).value()); + m_allocated |= 1uz << 0; } auto pml1 = (*pml2).next(pml2_index).value(); @@ -105,25 +111,34 @@ namespace teachos::memory::x86_64 auto pml2 = pml3->next(pml_index<3>(m_page)).value(); auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; - (*pml1)[pml_index<1>(m_page)].clear(); - if (pml1->empty()) + if (m_allocated & 1uz << 0) { - m_allocator->release(pml1_entry.frame().value()); + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } } - auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; - (*pml2)[pml_index<2>(m_page)].clear(); - if (pml2->empty()) + if (m_allocated & 1uz << 1) { - m_allocator->release(pml2_entry.frame().value()); + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } } - auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; - (*pml3)[pml_index<3>(m_page)].clear(); - if (pml3->empty()) + if (m_allocated & 1uz << 2) { - m_allocator->release(pml3_entry.frame().value()); + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } } m_mapped = false; -- cgit v1.2.3 From fc26187d9ace9798d9494341f3513eb0840b006d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:45:30 +0100 Subject: x86_64/memory: make scoped_mapping swappable --- .../include/x86_64/memory/scoped_mapping.hpp | 4 +++ arch/x86_64/src/memory/scoped_mapping.cpp | 31 +++++++++++++--------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index 99585bc..d4844fb 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -53,6 +53,8 @@ namespace teachos::memory::x86_64 //! @note If no frame was ever mapped, this function will panic. auto unmap() -> void; + auto swap(scoped_mapping & other) -> void; + private: page m_page; frame_allocator * m_allocator; @@ -60,6 +62,8 @@ namespace teachos::memory::x86_64 std::uint8_t m_allocated; }; + auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void; + } // namespace teachos::memory::x86_64 #endif \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index be15330..c9c6459 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -44,18 +44,7 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - if (&other == this) - { - return *this; - } - - using std::swap; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - + this->swap(other); return *this; } @@ -144,4 +133,22 @@ namespace teachos::memory::x86_64 m_mapped = false; } + auto scoped_mapping::swap(scoped_mapping & other) -> void + { + using std::swap; + + if (&other == this) + return; + + swap(m_page, other.m_page); + swap(m_allocator, other.m_allocator); + swap(m_mapped, other.m_mapped); + swap(m_allocated, other.m_allocated); + } + + auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void + { + lhs.swap(rhs); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 36cd516c84cf2edd16defcd39e99e2bee0bca892 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 4 Dec 2025 22:52:35 +0100 Subject: x86_64/memory: simplify initialization implementation --- arch/x86_64/src/kapi/memory.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 0e4b78e..d09a4c1 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -30,18 +30,7 @@ namespace teachos::memory 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; - auto create_memory_information() -> x86_64::region_allocator::memory_information - { - auto const & mbi = boot::bootstrap_information.mbi; - auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; - auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; - - return {.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 = mbi->memory_map()}; - }; - + //! Instantiate a basic, memory region based, early frame allocator for remapping. auto create_early_frame_allocator() { auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map(); @@ -50,15 +39,27 @@ namespace teachos::memory system::panic("[x86_64] Failed to create early allocator, no memory map available."); } - return x86_64::region_allocator{create_memory_information()}; + auto const & mbi = boot::bootstrap_information.mbi; + auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; + auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; + + return x86_64::region_allocator{ + { + .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) -> void { using namespace x86_64; -- cgit v1.2.3 From c01073b04a6dcdf067342cf17fe5363a66d85eed Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 14:48:31 +0100 Subject: multiboot2: add range support to VLA tags --- libs/multiboot2/include/multiboot2/impl/tag.hpp | 85 +++++++++++++++++++++- libs/multiboot2/include/multiboot2/information.hpp | 25 +------ 2 files changed, 84 insertions(+), 26 deletions(-) diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index f151b54..5edcd6f 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace multiboot2::impl @@ -79,7 +80,18 @@ namespace multiboot2::impl template typename Range> struct vla_tag : tag { - using range_type = Range; + using range_type = Range; + + 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; + 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; vla_tag() : tag{} @@ -91,10 +103,75 @@ namespace multiboot2::impl , m_vla{vla_start(header), vla_size(header)} {} - protected: + [[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(); + } + + private: auto static vla_start(tag_header const * header) noexcept -> VlaData * { - auto raw = std::bit_cast(header); + auto raw = std::bit_cast(header); auto start = raw + sizeof(tag); return std::bit_cast(start); } @@ -107,7 +184,7 @@ namespace multiboot2::impl return size; } - range_type const m_vla; + range_type m_vla; }; } // namespace multiboot2::impl diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 462528d..4be32aa 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -46,7 +46,7 @@ namespace multiboot2 */ auto string() const noexcept -> range_type { - return m_vla; + return {data(), size()}; } }; @@ -58,13 +58,6 @@ namespace multiboot2 { using base = impl::vla_tag const, std::span>; using base::base; - - using iterator = base::range_type::iterator; - - auto data() const noexcept -> base::range_type - { - return this->m_vla; - } }; /** @@ -79,7 +72,7 @@ namespace multiboot2 */ auto string() const noexcept -> std::string_view { - return m_vla; + return {data(), size()}; } }; @@ -90,24 +83,12 @@ namespace multiboot2 { using vla_tag::vla_tag; - using iterator = range_type::iterator; - - auto begin() const noexcept -> iterator - { - return regions().begin(); - } - - auto end() const noexcept -> iterator - { - return regions().end(); - } - /** * @brief The available memory regions */ auto regions() const noexcept -> range_type { - return m_vla; + return {data(), size()}; } }; -- cgit v1.2.3 From 53402f496ee07351923945f523565f9aa618005a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 15:13:57 +0100 Subject: elf: add basic section_header flag tests --- libs/elf/include/elf/section_header.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp index 73e2e7b..3afe334 100644 --- a/libs/elf/include/elf/section_header.hpp +++ b/libs/elf/include/elf/section_header.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace elf { @@ -60,6 +61,24 @@ namespace elf 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 @@ -74,6 +93,7 @@ namespace elf static_assert(sizeof(section_header) == section_header_size); static_assert(sizeof(section_header) == section_header_size); + } // namespace elf #endif \ No newline at end of file -- cgit v1.2.3 From 1124eb4e0a88e7cd13d6ebd9820d6ddcde343110 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 18:22:53 +0100 Subject: multiboot2: implement section name reading --- libs/multiboot2/include/multiboot2/impl/tag.hpp | 20 ++++++++++++++++---- libs/multiboot2/include/multiboot2/information.hpp | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index 5edcd6f..a6e2678 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -82,16 +82,18 @@ namespace multiboot2::impl { using range_type = Range; + 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; - 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; vla_tag() : tag{} @@ -168,6 +170,16 @@ namespace multiboot2::impl 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 * { diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 4be32aa..25f034d 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,19 @@ namespace multiboot2 { using base = impl::vla_tag const, std::span>; using base::base; + + [[nodiscard]] auto name(elf::section_header 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(string_table.virtual_load_address); + return name_array + name_offset; + } }; /** -- cgit v1.2.3 From 178d566278f580ed5625d2d34831b4d263ee09af Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 18:33:01 +0100 Subject: multiboot2: silence some warnings --- .vscode/settings.json | 8 ++-- libs/multiboot2/include/multiboot2/impl/data.hpp | 12 +++--- libs/multiboot2/include/multiboot2/impl/ids.hpp | 8 ++-- .../include/multiboot2/impl/iterator.hpp | 2 + libs/multiboot2/include/multiboot2/impl/tag.hpp | 21 ++++++----- libs/multiboot2/include/multiboot2/information.hpp | 44 +++++++++++----------- 6 files changed, 53 insertions(+), 42 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4f3f047..72a3903 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,17 +22,19 @@ ] }, "cSpell.words": [ + "acpi", "crtc", "efer", - "INTERPROCEDURAL", + "interprocedural", "invlpg", + "iwyu", "kapi", "kstd", "multiboot", - "NOLINTNEXTLINE", + "nolintnextline", "rdmsr", "rvalues", - "TeachOS", + "teachos", "wrmsr" ] } \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index 3cda162..733ce3a 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_DATA_HPP #define MULTIBOOT2_IMPL_DATA_HPP +// IWYU pragma: private + #include "multiboot2/impl/ids.hpp" #include @@ -23,14 +25,14 @@ namespace multiboot2::impl * * The maximum possible value for this field is 640 KiB. */ - std::uint32_t const lower_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 const upper_KiB; + std::uint32_t upper_KiB; }; /** @@ -94,7 +96,7 @@ namespace multiboot2::impl /** * @brief Check if the memory described by this region is available for use. */ - constexpr auto available() const noexcept + [[nodiscard]] constexpr auto available() const noexcept { return type == memory_type::AVAILABLE; } @@ -120,12 +122,12 @@ namespace multiboot2::impl /** * @brief Size of each entry present in the map */ - std::uint32_t const entry_size; + std::uint32_t entry_size; /** * @brief Version of each entry present in the map */ - std::uint32_t const entry_version; + std::uint32_t entry_version; }; } // namespace multiboot2::impl diff --git a/libs/multiboot2/include/multiboot2/impl/ids.hpp b/libs/multiboot2/include/multiboot2/impl/ids.hpp index 3a7215e..98bc1f2 100644 --- a/libs/multiboot2/include/multiboot2/impl/ids.hpp +++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_IDS_HPP #define MULTIBOOT2_IMPL_IDS_HPP +// IWYU pragma: private + #include namespace multiboot2::impl @@ -24,14 +26,14 @@ namespace multiboot2::impl 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. }; diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index f8955cb..5651f22 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -1,6 +1,8 @@ #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" diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index a6e2678..3d0cea5 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_TAG_HPP #define MULTIBOOT2_IMPL_TAG_HPP +// IWYU pragma: private + #include "multiboot2/impl/ids.hpp" #include @@ -25,29 +27,30 @@ namespace multiboot2::impl : tag_header{*data} {} - auto full_size() const noexcept -> std::size_t + [[nodiscard]] auto full_size() const noexcept -> std::size_t { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) return (m_size + 7) & (~7); } - auto information_id() const noexcept -> impl::information_id const & + [[nodiscard]] auto information_id() const noexcept -> impl::information_id const & { return m_id; } - auto next() const noexcept -> tag_header const * + [[nodiscard]] auto next() const noexcept -> tag_header const * { - return std::bit_cast(std::bit_cast(this) + full_size()); + return std::bit_cast(std::bit_cast(this) + full_size()); } - auto unaligned_size() const noexcept -> std::uint32_t + [[nodiscard]] auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } - protected: - impl::information_id const m_id; - std::uint32_t const m_size; + private: + impl::information_id m_id; + std::uint32_t m_size; }; /** @@ -64,7 +67,7 @@ namespace multiboot2::impl explicit tag(tag_header const * header) requires(sizeof(tag) > sizeof(tag_header)) : tag_header{header} - , Data{*std::bit_cast(header + 1)} + , Data{*std::bit_cast(header + 1)} // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) {} explicit tag(tag_header const * header) diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 25f034d..2d60a6d 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -45,7 +45,7 @@ namespace multiboot2 /** * @brief The command line string */ - auto string() const noexcept -> range_type + [[nodiscard]] auto string() const noexcept -> range_type { return {data(), size()}; } @@ -84,7 +84,7 @@ namespace multiboot2 /** * @brief The name of the bootloader */ - auto string() const noexcept -> std::string_view + [[nodiscard]] auto string() const noexcept -> std::string_view { return {data(), size()}; } @@ -100,7 +100,7 @@ namespace multiboot2 /** * @brief The available memory regions */ - auto regions() const noexcept -> range_type + [[nodiscard]] auto regions() const noexcept -> range_type { return {data(), size()}; } @@ -113,19 +113,19 @@ namespace multiboot2 using pointer = impl::information_iterator::pointer; using reference = impl::information_iterator::reference; - auto size_bytes() const noexcept -> std::size_t + [[nodiscard]] auto size_bytes() const noexcept -> std::size_t { return m_size; } // Range access - auto begin() const noexcept -> iterator + [[nodiscard]] auto begin() const noexcept -> iterator { return iterator{&m_tags}; } - auto end() const noexcept -> iterator + [[nodiscard]] auto end() const noexcept -> iterator { return iterator{}; } @@ -133,43 +133,43 @@ namespace multiboot2 // Tag access template - auto has() const noexcept -> bool + [[nodiscard]] auto has() const noexcept -> bool { return get().has_value(); } - auto maybe_basic_memory() const noexcept -> std::optional + [[nodiscard]] auto maybe_basic_memory() const noexcept -> std::optional { return get(); } - auto basic_memory() const -> basic_memory + [[nodiscard]] auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } - auto maybe_bios_boot_device() const noexcept -> std::optional + [[nodiscard]] auto maybe_bios_boot_device() const noexcept -> std::optional { return get(); } - auto bios_boot_device() const -> bios_boot_device + [[nodiscard]] auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } - auto maybe_command_line() const noexcept -> std::optional + [[nodiscard]] auto maybe_command_line() const noexcept -> std::optional { return get(); } - auto command_line() const -> command_line + [[nodiscard]] auto command_line() const -> command_line { return maybe_command_line().value(); } template - auto maybe_elf_symbols() const noexcept -> std::optional> + [[nodiscard]] auto maybe_elf_symbols() const noexcept -> std::optional> { return get>().and_then( [](auto x) -> std::optional> { @@ -185,34 +185,34 @@ namespace multiboot2 } template - auto elf_symbols() const -> elf_symbols + [[nodiscard]] auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } - auto maybe_loader_name() const noexcept -> std::optional + [[nodiscard]] auto maybe_loader_name() const noexcept -> std::optional { return get(); } - auto loader_name() const -> loader_name + [[nodiscard]] auto loader_name() const -> loader_name { return maybe_loader_name().value(); } - auto maybe_memory_map() const noexcept -> std::optional + [[nodiscard]] auto maybe_memory_map() const noexcept -> std::optional { return get(); } - auto memory_map() const -> memory_map + [[nodiscard]] auto memory_map() const -> memory_map { return maybe_memory_map().value(); } private: template - constexpr auto get() const noexcept -> std::optional + [[nodiscard]] constexpr auto get() const noexcept -> std::optional { if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); found != end()) @@ -222,9 +222,9 @@ namespace multiboot2 return std::nullopt; } - [[maybe_unused]] uint32_t const m_size{}; + uint32_t m_size{}; uint32_t : 32; - impl::tag_header const m_tags{}; + impl::tag_header m_tags{}; }; } // namespace multiboot2 -- cgit v1.2.3 From fc6d44be383213b7609b5e3c4778e235fb6b00c3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 18:48:44 +0100 Subject: kstd: implement memcmp --- libs/kstd/CMakeLists.txt | 1 + libs/kstd/src/libc/string.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 75c2315..e0c551c 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -4,6 +4,7 @@ add_library("libs::kstd" ALIAS "kstd") set(KSTD_LIBC_SYMBOLS "abort" "strlen" + "memcmp" ) target_sources("kstd" PRIVATE diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp index a42aedc..a9b85fc 100644 --- a/libs/kstd/src/libc/string.cpp +++ b/libs/kstd/src/libc/string.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace kstd::libc { @@ -10,6 +11,20 @@ namespace kstd::libc { 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(lhs), size}; + auto right_span = std::span{static_cast(rhs), size}; + auto mismatched = std::ranges::mismatch(left_span, right_span); + + if (mismatched.in1 == left_span.end()) + { + return 0; + } + + return std::bit_cast(*mismatched.in1) - std::bit_cast(*mismatched.in2); + } } } // namespace kstd::libc \ No newline at end of file -- cgit v1.2.3 From 448a79328544e3ecb72d0b3b95c0b9b0d49faafc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 12:27:37 +0100 Subject: x86_64/memory: fix scoped_mapping unmap logic --- arch/x86_64/src/memory/scoped_mapping.cpp | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index c9c6459..44dbf45 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -96,38 +96,32 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml4 = &paging_root::get(); + auto pml3 = pml4->next(pml_index<4>(m_page)).value(); auto pml2 = pml3->next(pml_index<3>(m_page)).value(); auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + (*pml1)[pml_index<1>(m_page)].clear(); + if (m_allocated & 1uz << 0) { - auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; - (*pml1)[pml_index<1>(m_page)].clear(); - if (pml1->empty()) - { - m_allocator->release(pml1_entry.frame().value()); - } + auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); + m_allocator->release(pml1_frame); + (*pml2)[pml_index<2>(m_page)].clear(); } if (m_allocated & 1uz << 1) { - auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; - (*pml2)[pml_index<2>(m_page)].clear(); - if (pml2->empty()) - { - m_allocator->release(pml2_entry.frame().value()); - } + auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); + m_allocator->release(pml2_frame); + (*pml3)[pml_index<3>(m_page)].clear(); } if (m_allocated & 1uz << 2) { - auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; - (*pml3)[pml_index<3>(m_page)].clear(); - if (pml3->empty()) - { - m_allocator->release(pml3_entry.frame().value()); - } + auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); + m_allocator->release(pml3_frame); + (*pml4)[pml_index<4>(m_page)].clear(); } m_mapped = false; -- cgit v1.2.3 From b9d445bf92725d79269becf978059e040519c00a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 16:51:44 +0100 Subject: x86_64/memory: implement simple kernel remapper --- .vscode/settings.json | 1 + arch/x86_64/CMakeLists.txt | 1 + .../x86_64/include/x86_64/memory/kernel_mapper.hpp | 33 +++++++ arch/x86_64/include/x86_64/memory/page_table.hpp | 16 +++ arch/x86_64/include/x86_64/memory/paging_root.hpp | 8 ++ arch/x86_64/src/kapi/memory.cpp | 20 ++-- arch/x86_64/src/memory/kernel_mapper.cpp | 107 +++++++++++++++++++++ arch/x86_64/src/memory/page_table.cpp | 13 +++ arch/x86_64/src/memory/paging_root.cpp | 55 ++++++++++- 9 files changed, 247 insertions(+), 7 deletions(-) create mode 100644 arch/x86_64/include/x86_64/memory/kernel_mapper.hpp create mode 100644 arch/x86_64/src/memory/kernel_mapper.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 72a3903..c0f3e5d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -30,6 +30,7 @@ "iwyu", "kapi", "kstd", + "memcmp", "multiboot", "nolintnextline", "rdmsr", diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 7f01744..0b9009c 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources("x86_64" PRIVATE "src/kapi/memory.cpp" # Memory management + "src/memory/kernel_mapper.cpp" "src/memory/mmu.cpp" "src/memory/page_table.cpp" "src/memory/paging_root.cpp" 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..4b681ae --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp @@ -0,0 +1,33 @@ +#ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP +#define TEACHOS_X86_64_KERNEL_MAPPER_HPP + +#include "kapi/memory.hpp" + +#include +#include +#include + +#include + +namespace teachos::memory::x86_64 +{ + + struct kernel_mapper + { + using section_header_type = elf::section_header; + + kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi); + + auto remap_kernel() -> void; + + private: + auto map_section(section_header_type const & section, std::string_view name) -> void; + + frame_allocator * m_allocator; + 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/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp index c5102a2..ce34e23 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -51,6 +51,12 @@ namespace teachos::memory::x86_64 //! Get all flags present in this entry. [[nodiscard]] auto all_flags() const -> flags; + //! Set the flags of this entry to the given set. + auto all_flags(flags flags) -> void; + + //! Additively set the given flags in this entry. + auto operator|=(flags rhs) -> entry &; + //! Get the frame number associated with this entry, if the referenced page is present. [[nodiscard]] auto frame() const -> std::optional; @@ -86,11 +92,21 @@ namespace teachos::memory::x86_64 return std::bit_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); } + constexpr auto operator|=(page_table::entry::flags & lhs, page_table::entry::flags rhs) -> page_table::entry::flags & + { + return lhs = lhs | rhs; + } + constexpr auto operator&(page_table::entry::flags lhs, page_table::entry::flags rhs) -> page_table::entry::flags { return std::bit_cast(std::to_underlying(lhs) & std::to_underlying(rhs)); } + constexpr auto operator~(page_table::entry::flags flags) + { + return std::bit_cast(~std::to_underlying(flags)); + } + //! A recursively mapped page table. template requires(Level > 0uz && Level < 5uz) diff --git a/arch/x86_64/include/x86_64/memory/paging_root.hpp b/arch/x86_64/include/x86_64/memory/paging_root.hpp index a9ab6a6..d4aa023 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -25,6 +25,14 @@ namespace teachos::memory::x86_64 [[nodiscard]] auto translate(linear_address address) const -> std::optional; [[nodiscard]] auto translate(page page) const -> std::optional; + //! Map the given page into the given frame using the given flags. + //! + //! @param page A page to map. + //! @param frame The frame into which to map the page. + //! @param flags The flags to apply to the mapping. + //! @param allocator The frame allocator used to allocate any required page tables. + auto map(page page, frame frame, entry::flags flags, frame_allocator & allocator) -> std::optional; + private: paging_root() = default; }; diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index d09a4c1..ed3edef 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,11 +1,14 @@ #include "kapi/memory.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/impl/control_registers.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" @@ -60,7 +63,7 @@ namespace teachos::memory } //! Inject, or graft, a faux recursive PML4 into the active page mapping structure. - auto inject_faux_pml4(frame_allocator & allocator) -> void + auto inject_faux_pml4(frame_allocator & allocator) { using namespace x86_64; using entry_flags = page_table::entry::flags; @@ -105,6 +108,8 @@ namespace teachos::memory auto new_pml1 = (**new_pml2).next(pml2_index); (**new_pml1)[pml1_index] = pml1_entry; + + return *new_pml4_frame; } } // namespace @@ -131,12 +136,15 @@ namespace teachos::memory enable_cpu_protections(); auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; - inject_faux_pml4(allocation_buffer); + auto new_pml4_frame = inject_faux_pml4(allocation_buffer); - // 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(); + auto mapper = x86_64::kernel_mapper{allocation_buffer, boot::bootstrap_information.mbi}; + mapper.remap_kernel(); + cio::println("[x86_64:MEM] prepared new kernel image page maps."); + + auto cr3 = cpu::x86_64::cr3::read(); + cr3.address(new_pml4_frame.start_address()); + cpu::x86_64::cr3::write(cr3); // 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); 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..b1d12a4 --- /dev/null +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -0,0 +1,107 @@ +#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 "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +#include +#include + +#include +#include + +namespace teachos::memory::x86_64 +{ + + inline 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(frame_allocator & allocator, multiboot2::information_view const * mbi) + : m_allocator{&allocator} + , m_mbi(std::move(mbi)) + , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} + {} + + auto kernel_mapper::remap_kernel() -> void + { + auto elf_information = m_mbi->maybe_elf_symbols(); + 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::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)); }); + } + + auto kernel_mapper::map_section(section_header_type const & section, std::string_view name) -> 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_table::entry::flags::empty; + + if (section.writable()) + { + page_flags |= page_table::entry::flags::writable; + } + + if (!section.executable()) + { + page_flags |= page_table::entry::flags::no_execute; + } + + 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_table::entry::flags::user_accessible; + } + + for (auto i = 0uz; i < number_of_pages; ++i) + { + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + } + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 60bf94d..e797b22 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -1,6 +1,7 @@ #include "x86_64/memory/page_table.hpp" #include +#include namespace teachos::memory::x86_64 { @@ -25,6 +26,18 @@ namespace teachos::memory::x86_64 return std::bit_cast(m_raw & ~frame_number_mask); } + auto page_table::entry::all_flags(flags flags) -> void + { + m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags); + } + + auto page_table::entry::operator|=(flags rhs) -> 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 -> std::optional { if (present()) diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b8e1ab..5ca2bf0 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,10 +1,15 @@ #include "x86_64/memory/paging_root.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/scoped_mapping.hpp" +#include #include +#include #include namespace teachos::memory::x86_64 @@ -13,7 +18,45 @@ namespace teachos::memory::x86_64 namespace { constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; - } + + //! 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 + requires(Level > 1uz && Level < 5uz) + auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags, + frame_allocator & allocator) + { + auto index = pml_index(page); + flags = flags & ~page_table::entry::flags::no_execute; + flags = flags | page_table::entry::flags::writable; + if (!(*pml)[index].present()) + { + auto new_table_frame = allocator.allocate(); + auto mapping = scoped_mapping{page, allocator}; + (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); + auto new_table = std::optional{std::construct_at(*pml->next(index))}; + return new_table; + } + (*pml)[index] |= flags; + return pml->next(index); + } + + //! Perform the actual PML1 update. + auto do_map(page_table * pml, page page, frame frame, page_table::entry::flags flags) -> std::optional + { + 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 | flags); + return std::optional{static_cast(page.start_address())}; + } + } // namespace auto paging_root::get() -> paging_root & { @@ -71,4 +114,14 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } + auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) + -> std::optional + { + return std::optional{this} + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From f0c5ac3c8222d4d89b8e2d2a726427a7ec64e538 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 17:20:14 +0100 Subject: kstd: extract bitwise enum operations --- .clang-format | 2 + .../include/x86_64/cpu/impl/control_registers.hpp | 77 +++++----------------- .../x86_64/cpu/impl/model_specific_register.hpp | 44 ++++--------- arch/x86_64/include/x86_64/memory/page_table.hpp | 31 ++++----- libs/kstd/CMakeLists.txt | 2 + libs/kstd/include/kstd/ext/bitfield_enum | 64 ++++++++++++++++++ 6 files changed, 110 insertions(+), 110 deletions(-) create mode 100644 libs/kstd/include/kstd/ext/bitfield_enum diff --git a/.clang-format b/.clang-format index a47e396..e54cb03 100644 --- a/.clang-format +++ b/.clang-format @@ -61,6 +61,8 @@ IncludeCategories: Priority: 110 - Regex: '"[[:alnum:]._\/]+\.hpp"' Priority: 300 + - Regex: '' + Priority: 400 - Regex: '<[[:alnum:]._\/]+\.hpp>' Priority: 600 - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' diff --git a/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp index d892360..0c2254a 100644 --- a/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp @@ -1,8 +1,12 @@ #ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP #define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP +// IWYU pragma: private + #include "kapi/memory/address.hpp" +#include + #include #include #include @@ -83,72 +87,12 @@ namespace teachos::cpu::x86_64 paging = 1uz << 31 }; - constexpr auto operator|(cr0_flags lhs, cr0_flags rhs) -> cr0_flags - { - return static_cast(static_cast>(lhs) | - static_cast>(rhs)); - } - - constexpr auto operator|=(cr0_flags & lhs, cr0_flags rhs) -> cr0_flags & - { - lhs = lhs | rhs; - return lhs; - } - - constexpr auto operator&(cr0_flags lhs, cr0_flags rhs) -> cr0_flags - { - return static_cast(static_cast>(lhs) & - static_cast>(rhs)); - } - - constexpr auto operator&=(cr0_flags & lhs, cr0_flags rhs) -> cr0_flags & - { - lhs = lhs & rhs; - return lhs; - } - - constexpr auto operator~(cr0_flags lhs) -> cr0_flags - { - // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) - return static_cast(~static_cast>(lhs)); - } - enum struct cr3_flags : std::uint64_t { page_level_write_through = 1uz << 0, page_level_cache_disable = 1uz << 1, }; - constexpr auto operator|(cr3_flags lhs, cr3_flags rhs) -> cr3_flags - { - return static_cast(static_cast>(lhs) | - static_cast>(rhs)); - } - - constexpr auto operator|=(cr3_flags & lhs, cr3_flags rhs) -> cr3_flags & - { - lhs = lhs | rhs; - return lhs; - } - - constexpr auto operator&(cr3_flags lhs, cr3_flags rhs) -> cr3_flags - { - return static_cast(static_cast>(lhs) & - static_cast>(rhs)); - } - - constexpr auto operator&=(cr3_flags & lhs, cr3_flags rhs) -> cr3_flags & - { - lhs = lhs & rhs; - return lhs; - } - - constexpr auto operator~(cr3_flags lhs) -> cr3_flags - { - // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) - return static_cast(~static_cast>(lhs)); - } - struct cr3_value { constexpr cr3_value() = default; @@ -193,4 +137,17 @@ namespace teachos::cpu::x86_64 } // namespace teachos::cpu::x86_64 +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; + + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + #endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp b/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp index 8a41a8a..ff2c8ad 100644 --- a/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp +++ b/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp @@ -1,6 +1,10 @@ #ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP #define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP +// IWYU pragma: private + +#include + #include #include #include @@ -73,40 +77,20 @@ namespace teachos::cpu::x86_64 execute_disable_bit_enable = 1uz << 11, }; - constexpr auto operator|(ia32_efer_flags lhs, ia32_efer_flags rhs) -> ia32_efer_flags - { - return static_cast(static_cast>(lhs) | - static_cast>(rhs)); - } - - constexpr auto operator|=(ia32_efer_flags & lhs, ia32_efer_flags rhs) -> ia32_efer_flags & - { - lhs = lhs | rhs; - return lhs; - } - - constexpr auto operator&(ia32_efer_flags lhs, ia32_efer_flags rhs) -> ia32_efer_flags - { - return static_cast(static_cast>(lhs) & - static_cast>(rhs)); - } - - constexpr auto operator&=(ia32_efer_flags & lhs, ia32_efer_flags rhs) -> ia32_efer_flags & - { - lhs = lhs & rhs; - return lhs; - } - - constexpr auto operator~(ia32_efer_flags lhs) -> ia32_efer_flags - { - // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) - return static_cast(~static_cast>(lhs)); - } - } // namespace impl using i32_efer = impl::model_specific_register; } // namespace teachos::cpu::x86_64 +namespace kstd::ext +{ + + template<> + struct is_bitfield_enum : std::true_type + { + }; + +} // namespace kstd::ext + #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 index ce34e23..22616e8 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -3,11 +3,14 @@ #include "kapi/memory.hpp" +#include + #include #include #include #include #include +#include #include namespace teachos::memory::x86_64 @@ -87,26 +90,6 @@ namespace teachos::memory::x86_64 std::array m_entries{}; }; - constexpr auto operator|(page_table::entry::flags lhs, page_table::entry::flags rhs) -> page_table::entry::flags - { - return std::bit_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); - } - - constexpr auto operator|=(page_table::entry::flags & lhs, page_table::entry::flags rhs) -> page_table::entry::flags & - { - return lhs = lhs | rhs; - } - - constexpr auto operator&(page_table::entry::flags lhs, page_table::entry::flags rhs) -> page_table::entry::flags - { - return std::bit_cast(std::to_underlying(lhs) & std::to_underlying(rhs)); - } - - constexpr auto operator~(page_table::entry::flags flags) - { - return std::bit_cast(~std::to_underlying(flags)); - } - //! A recursively mapped page table. template requires(Level > 0uz && Level < 5uz) @@ -155,4 +138,12 @@ namespace teachos::memory::x86_64 } // namespace teachos::memory::x86_64 +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + #endif \ No newline at end of file diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index e0c551c..d83e704 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -22,6 +22,8 @@ target_sources("kstd" PUBLIC "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" diff --git a/libs/kstd/include/kstd/ext/bitfield_enum b/libs/kstd/include/kstd/ext/bitfield_enum new file mode 100644 index 0000000..327af45 --- /dev/null +++ b/libs/kstd/include/kstd/ext/bitfield_enum @@ -0,0 +1,64 @@ +#ifndef KSTD_EXT_BITFIELD_ENUM_HPP +#define KSTD_EXT_BITFIELD_ENUM_HPP + +#include +#include +#include + +namespace kstd::ext +{ + + template + requires std::is_enum_v + struct is_bitfield_enum : std::false_type + { + }; + + template + concept bitfield_enum = is_bitfield_enum::value; + +}; // namespace kstd::ext + +template +constexpr auto operator|(EnumType lhs, EnumType rhs) -> EnumType +{ + return std::bit_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); +} + +template +constexpr auto operator|=(EnumType & lhs, EnumType rhs) -> EnumType & +{ + return lhs = lhs | rhs; +} + +template +constexpr auto operator&(EnumType lhs, EnumType rhs) -> EnumType +{ + return std::bit_cast(std::to_underlying(lhs) & std::to_underlying(rhs)); +} + +template +constexpr auto operator&=(EnumType & lhs, EnumType rhs) -> EnumType & +{ + return lhs = lhs & rhs; +} + +template +constexpr auto operator^(EnumType lhs, EnumType rhs) -> EnumType +{ + return std::bit_cast(std::to_underlying(lhs) ^ std::to_underlying(rhs)); +} + +template +constexpr auto operator^=(EnumType & lhs, EnumType rhs) -> EnumType & +{ + return lhs = lhs ^ rhs; +} + +template +constexpr auto operator~(EnumType lhs) -> EnumType +{ + return std::bit_cast(~std::to_underlying(lhs)); +} + +#endif \ No newline at end of file -- cgit v1.2.3 From eafbf588760c289b7f54a4771b39af0ccfe8cf59 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 21:55:42 +0100 Subject: kapi: extract page_mapper interface --- arch/x86_64/CMakeLists.txt | 1 + .../x86_64/include/x86_64/memory/kernel_mapper.hpp | 5 +- arch/x86_64/include/x86_64/memory/page_table.hpp | 65 ++++++++++++++ arch/x86_64/include/x86_64/memory/paging_root.hpp | 9 +- .../x86_64/memory/recursive_page_mapper.hpp | 23 +++++ .../include/x86_64/memory/scoped_mapping.hpp | 9 +- arch/x86_64/src/kapi/memory.cpp | 29 +++++-- arch/x86_64/src/memory/kernel_mapper.cpp | 7 +- arch/x86_64/src/memory/paging_root.cpp | 52 ++++++++++-- arch/x86_64/src/memory/recursive_page_mapper.cpp | 38 +++++++++ arch/x86_64/src/memory/scoped_mapping.cpp | 99 ++-------------------- kapi/CMakeLists.txt | 1 + kapi/include/kapi/memory.hpp | 2 + kapi/include/kapi/memory/page_mapper.hpp | 82 ++++++++++++++++++ 14 files changed, 300 insertions(+), 122 deletions(-) create mode 100644 arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp create mode 100644 arch/x86_64/src/memory/recursive_page_mapper.cpp create mode 100644 kapi/include/kapi/memory/page_mapper.hpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 0b9009c..7bd8d07 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -27,6 +27,7 @@ target_sources("x86_64" PRIVATE "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" diff --git a/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp index 4b681ae..1f217ae 100644 --- a/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp +++ b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP #define TEACHOS_X86_64_KERNEL_MAPPER_HPP -#include "kapi/memory.hpp" - #include #include #include @@ -16,14 +14,13 @@ namespace teachos::memory::x86_64 { using section_header_type = elf::section_header; - kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi); + explicit kernel_mapper(multiboot2::information_view const * mbi); auto remap_kernel() -> void; private: auto map_section(section_header_type const & section, std::string_view name) -> void; - frame_allocator * m_allocator; multiboot2::information_view const * m_mbi; std::uintptr_t m_kernel_load_base; }; diff --git a/arch/x86_64/include/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp index 22616e8..6a9c045 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -146,4 +146,69 @@ namespace kstd::ext }; } // 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; + } + + 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) != 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/paging_root.hpp b/arch/x86_64/include/x86_64/memory/paging_root.hpp index d4aa023..ed95106 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -30,8 +30,13 @@ namespace teachos::memory::x86_64 //! @param page A page to map. //! @param frame The frame into which to map the page. //! @param flags The flags to apply to the mapping. - //! @param allocator The frame allocator used to allocate any required page tables. - auto map(page page, frame frame, entry::flags flags, frame_allocator & allocator) -> std::optional; + auto map(page page, frame frame, entry::flags flags) -> std::optional; + + //! Unmap the given page from virtual memory. + //! + //! @warning If the page has not previously been mapped, this function will panic. + //! @param page The page to unmap + auto unmap(page) -> void; private: paging_root() = default; 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..a66c8d1 --- /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) -> 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/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index d4844fb..415ea8e 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -22,8 +22,7 @@ namespace teachos::memory::x86_64 //! 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 allocator An allocator to be used to allocate any page maps required to map the frame. - scoped_mapping(page page, frame_allocator & allocator); + explicit scoped_mapping(page page); //! Unmap the mapped frame if one was mapped. //! @note Any page tables that were allocated to support the mapping will be released. @@ -53,17 +52,13 @@ namespace teachos::memory::x86_64 //! @note If no frame was ever mapped, this function will panic. auto unmap() -> void; - auto swap(scoped_mapping & other) -> void; + friend auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void; private: page m_page; - frame_allocator * m_allocator; bool m_mapped; - std::uint8_t m_allocated; }; - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void; - } // namespace teachos::memory::x86_64 #endif \ No newline at end of file diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index ed3edef..00b9de3 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -13,6 +13,7 @@ #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" @@ -29,6 +30,8 @@ namespace teachos::memory { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + auto constinit mapper = static_cast(nullptr); 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; @@ -70,7 +73,7 @@ namespace teachos::memory auto page = page::containing(unused_page_address); - auto temporary_mapper = scoped_mapping{page, allocator}; + auto temporary_mapper = scoped_mapping{page}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as(*new_pml4_frame, entry_flags::writable)); @@ -124,6 +127,15 @@ namespace teachos::memory return *allocator; } + auto active_mapper() -> page_mapper & + { + if (!mapper) + { + system::panic("[x86_64] The page mapper has not been set you."); + } + return *mapper; + } + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -132,14 +144,19 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; + auto early_allocator = create_early_frame_allocator(); + auto allocation_buffer = x86_64::buffered_allocator<4>{&early_allocator}; + allocator = &allocation_buffer; + + auto recursive_mapper = x86_64::recursive_page_mapper{allocation_buffer}; + mapper = &recursive_mapper; + auto new_pml4_frame = inject_faux_pml4(allocation_buffer); - auto mapper = x86_64::kernel_mapper{allocation_buffer, boot::bootstrap_information.mbi}; - mapper.remap_kernel(); + auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi}; + kernel_mapper.remap_kernel(); cio::println("[x86_64:MEM] prepared new kernel image page maps."); auto cr3 = cpu::x86_64::cr3::read(); @@ -149,6 +166,8 @@ namespace teachos::memory // 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(); + mapper = nullptr; + allocator = nullptr; } } // namespace teachos::memory diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index b1d12a4..f46b5b5 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -32,9 +32,8 @@ namespace teachos::memory::x86_64 } // namespace - kernel_mapper::kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi) - : m_allocator{&allocator} - , m_mbi(std::move(mbi)) + kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi) + : m_mbi{std::move(mbi)} , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} {} @@ -100,7 +99,7 @@ namespace teachos::memory::x86_64 for (auto i = 0uz; i < number_of_pages; ++i) { - paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags); } } diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 5ca2bf0..c458093 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -27,16 +27,15 @@ namespace teachos::memory::x86_64 //! still enforcing non-writability and non-execution of the affected page. template requires(Level > 1uz && Level < 5uz) - auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags, - frame_allocator & allocator) + auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags) { auto index = pml_index(page); flags = flags & ~page_table::entry::flags::no_execute; flags = flags | page_table::entry::flags::writable; if (!(*pml)[index].present()) { - auto new_table_frame = allocator.allocate(); - auto mapping = scoped_mapping{page, allocator}; + auto new_table_frame = active_allocator().allocate(); + auto mapping = scoped_mapping{page}; (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); auto new_table = std::optional{std::construct_at(*pml->next(index))}; return new_table; @@ -114,14 +113,49 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } - auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) - -> std::optional + auto paging_root::map(page page, frame frame, page_table::entry::flags flags) -> std::optional { return std::optional{this} - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); } + auto paging_root::unmap(page page) -> void + { + if (!this->translate(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + + auto pml4 = this; + 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(); + active_allocator().release(pml1_frame); + (*pml2)[pml_index<2>(page)].clear(); + } + + if (pml2->empty()) + { + auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); + active_allocator().release(pml2_frame); + (*pml3)[pml_index<3>(page)].clear(); + } + + if (pml3->empty()) + { + auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); + active_allocator().release(pml3_frame); + (*pml4)[pml_index<4>(page)].clear(); + } + } + } // 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..ea89f38 --- /dev/null +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -0,0 +1,38 @@ +#include "x86_64/memory/recursive_page_mapper.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +namespace teachos::memory::x86_64 +{ + 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 * + { + return paging_root::get().map(page, frame, to_table_flags(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) -> bool + { + auto & root = paging_root::get(); + if (!root.translate(page)) + { + return false; + } + root.unmap(page); + return true; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 44dbf45..6f3461c 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -5,10 +5,8 @@ #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 #include namespace teachos::memory::x86_64 @@ -16,16 +14,12 @@ namespace teachos::memory::x86_64 scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} - , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} - , m_allocated{std::exchange(other.m_allocated, 0)} {} - scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + scoped_mapping::scoped_mapping(page page) : m_page{page} - , m_allocator{&allocator} , m_mapped{false} - , m_allocated{} { if (paging_root::get().translate(page)) { @@ -44,105 +38,28 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - this->swap(other); + swap(*this, other); return *this; } auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto & pml4 = paging_root::get(); - auto pml4_index = pml_index<4>(m_page); - if (!pml4[pml4_index].present()) - { - auto new_frame = m_allocator->allocate(); - pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at(pml4.next(pml4_index).value()); - m_allocated |= 1uz << 2; - } - - auto pml3 = pml4.next(pml4_index).value(); - auto pml3_index = pml_index<3>(m_page); - if (!(*pml3)[pml3_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml3).next(pml3_index).value()); - m_allocated |= 1uz << 1; - } - - auto pml2 = (*pml3).next(pml3_index).value(); - auto pml2_index = pml_index<2>(m_page); - if (!(*pml2)[pml2_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml2).next(pml2_index).value()); - m_allocated |= 1uz << 0; - } - - auto pml1 = (*pml2).next(pml2_index).value(); - auto pml1_index = pml_index<1>(m_page); - (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); - + auto result = active_mapper().map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; - - return static_cast(m_page.start_address()); + return result; } auto scoped_mapping::unmap() -> void { - if (!m_mapped) - { - system::panic("[MEM] Tried to release an unmapped temporary mapping!"); - } - - auto pml4 = &paging_root::get(); - auto pml3 = pml4->next(pml_index<4>(m_page)).value(); - auto pml2 = pml3->next(pml_index<3>(m_page)).value(); - auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - - (*pml1)[pml_index<1>(m_page)].clear(); - - if (m_allocated & 1uz << 0) - { - auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); - m_allocator->release(pml1_frame); - (*pml2)[pml_index<2>(m_page)].clear(); - } - - if (m_allocated & 1uz << 1) - { - auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); - m_allocator->release(pml2_frame); - (*pml3)[pml_index<3>(m_page)].clear(); - } - - if (m_allocated & 1uz << 2) - { - auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); - m_allocator->release(pml3_frame); - (*pml4)[pml_index<4>(m_page)].clear(); - } - + active_mapper().unmap(m_page); m_mapped = false; } - auto scoped_mapping::swap(scoped_mapping & other) -> void - { - using std::swap; - - if (&other == this) - return; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - } - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void { - lhs.swap(rhs); + using std::swap; + swap(lhs.m_page, rhs.m_page); + swap(lhs.m_mapped, rhs.m_mapped); } } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index ca26615..d0ecb70 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources("kapi" PUBLIC "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" ) diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp index 4279274..9ca1267 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/include/kapi/memory.hpp @@ -5,10 +5,12 @@ #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 namespace teachos::memory { auto active_allocator() -> frame_allocator &; + auto active_mapper() -> page_mapper &; auto init() -> void; } // namespace teachos::memory diff --git a/kapi/include/kapi/memory/page_mapper.hpp b/kapi/include/kapi/memory/page_mapper.hpp new file mode 100644 index 0000000..aa5cf76 --- /dev/null +++ b/kapi/include/kapi/memory/page_mapper.hpp @@ -0,0 +1,82 @@ +#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 + +#include + +namespace teachos::memory +{ + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) + struct page_mapper + { + enum struct flags : std::uint64_t + { + empty, + writable = 1 << 0, + executable = 1 << 1, + uncached = 1 << 2, + supervisor = 1 << 3, + }; + + 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, this function will 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) -> bool = 0; + + /** + * 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 + [[nodiscard]] auto map_as(page page, frame frame, flags flags) -> T * + { + return std::bit_cast(map(page, frame, flags)); + } + }; + +} // namespace teachos::memory + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + +#endif \ No newline at end of file -- cgit v1.2.3 From 998a001fc621ca0e7560ca09a8acd29469ae3373 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 17:46:02 +0100 Subject: docs: improve documentation --- CMakeLists.txt | 14 + Doxyfile | 2974 ++++++++++++++++++++ arch/x86_64/include/x86_64/boot/ld.hpp | 95 +- .../include/x86_64/cpu/impl/control_registers.hpp | 339 ++- .../include/x86_64/memory/buffered_allocator.hpp | 2 +- arch/x86_64/include/x86_64/memory/page_table.hpp | 145 +- arch/x86_64/include/x86_64/memory/paging_root.hpp | 2 +- .../include/x86_64/memory/region_allocator.hpp | 94 +- arch/x86_64/src/memory/page_table.cpp | 18 +- arch/x86_64/src/memory/region_allocator.cpp | 2 +- arch/x86_64/x86_64.dox | 14 + kapi/include/kapi/memory/frame.hpp | 68 +- kapi/include/kapi/memory/frame_allocator.hpp | 24 +- libs/kstd/include/kstd/ext/bitfield_enum | 1 + libs/kstd/kstd.dox | 14 + 15 files changed, 3498 insertions(+), 308 deletions(-) create mode 100644 Doxyfile create mode 100644 arch/x86_64/x86_64.dox create mode 100644 libs/kstd/kstd.dox diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e53923..9c348d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,20 @@ if(CLANG_TIDY_EXE AND TEACHOS_ENABLE_LINTING) set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}") endif() +#[============================================================================[ +# Global Documentation Configuration +#]============================================================================] + +find_package(Doxygen "1.10") + +if(Doxygen_FOUND) + doxygen_add_docs("docs" + ALL + COMMENT "Generating documentation" + CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile" + ) +endif() + #[============================================================================[ # Kernel Executable #]============================================================================] 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 ... \endif and \cond +# ... \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: +# +# +# +# where is the value of the INPUT_FILTER tag, and 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-.js script +# (where 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 + S +# (what the is depends on the OS and browser, but it is typically +# , /