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(-) (limited to 'arch/x86_64/include') 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 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 --- .../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 -------------------- 7 files changed, 39 insertions(+), 208 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 (limited to 'arch/x86_64/include') 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 -- 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 -------------------------------- 1 file changed, 601 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/vector.hpp (limited to 'arch/x86_64/include') 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 -- 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 ------------------------ 1 file changed, 204 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/unique_pointer.hpp (limited to 'arch/x86_64/include') 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 -- 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 ------------------------ 1 file changed, 269 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/shared_pointer.hpp (limited to 'arch/x86_64/include') 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 -- 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 (limited to 'arch/x86_64/include') 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 --------------------------------- 1 file changed, 212 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/stack.hpp (limited to 'arch/x86_64/include') 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 -- 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 (limited to 'arch/x86_64/include') 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 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/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 ++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 208 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 (limited to 'arch/x86_64/include') 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 -- 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 --- .../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 +++++++++++++++++ 5 files changed, 224 insertions(+), 92 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 (limited to 'arch/x86_64/include') 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 -- 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/include/x86_64/boot/boot.hpp | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 arch/x86_64/include/x86_64/boot/boot.hpp (limited to 'arch/x86_64/include') 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 -- 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/x86_64/include/x86_64/boot/boot.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/include') 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 -- 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 (limited to 'arch/x86_64/include') 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 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 arch/x86_64/include/x86_64/boot/ld.hpp (limited to 'arch/x86_64/include') 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 -- 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(-) (limited to 'arch/x86_64/include') 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 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/include') 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 -- 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 ------- 4 files changed, 167 insertions(+), 171 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 (limited to 'arch/x86_64/include') 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 -- 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/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 ++++++++ 5 files changed, 99 insertions(+), 113 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 (limited to 'arch/x86_64/include') 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 -- 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 -- 50 files changed, 3223 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 (limited to 'arch/x86_64/include') 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 -- 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/include/x86_64/vga/text.hpp | 122 +++++++++++++------------------- 1 file changed, 48 insertions(+), 74 deletions(-) (limited to 'arch/x86_64/include') 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 -- 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 +- 10 files changed, 34 insertions(+), 172 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 (limited to 'arch/x86_64/include') 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 -- 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 --- arch/x86_64/include/x86_64/memory/region_allocator.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/include') 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: /** -- 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(-) (limited to 'arch/x86_64/include') 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 --- 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 ++++++++++++++++++++-------- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'arch/x86_64/include') 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: /** -- 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 --- .../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 ++++++++++++++-------- 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'arch/x86_64/include') 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 -- 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 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/x86_64/include') 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; }; -- 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 --- .../include/x86_64/cpu/impl/control_registers.hpp | 196 +++++++++++++++++++++ arch/x86_64/include/x86_64/cpu/registers.hpp | 68 +------ 2 files changed, 197 insertions(+), 67 deletions(-) create mode 100644 arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp (limited to 'arch/x86_64/include') 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 -- 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 --- .../x86_64/cpu/impl/model_specific_register.hpp | 112 +++++++++++++++++++++ arch/x86_64/include/x86_64/cpu/registers.hpp | 3 +- 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp (limited to 'arch/x86_64/include') 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 -- 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 --- 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 +++++++++++ 3 files changed, 30 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/include') 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 -- 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/include/x86_64/memory/page_table.hpp | 139 ++++++++++++++++++++++ arch/x86_64/include/x86_64/memory/paging_root.hpp | 27 +++++ 2 files changed, 166 insertions(+) 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 (limited to 'arch/x86_64/include') 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 -- 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(+) (limited to 'arch/x86_64/include') 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 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 --- .../include/x86_64/memory/scoped_mapping.hpp | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 arch/x86_64/include/x86_64/memory/scoped_mapping.hpp (limited to 'arch/x86_64/include') 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 -- 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 --- .../include/x86_64/memory/page_utilities.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 arch/x86_64/include/x86_64/memory/page_utilities.hpp (limited to 'arch/x86_64/include') 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 -- 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 +++ arch/x86_64/include/x86_64/memory/scoped_mapping.hpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/include') 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; }; -- 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 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/include') 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; -- 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 --- .../include/x86_64/memory/buffered_allocator.hpp | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 arch/x86_64/include/x86_64/memory/buffered_allocator.hpp (limited to 'arch/x86_64/include') 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 -- 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(-) (limited to 'arch/x86_64/include') 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 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 --- arch/x86_64/include/x86_64/memory/scoped_mapping.hpp | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/x86_64/include') 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 -- 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 --- arch/x86_64/include/x86_64/memory/scoped_mapping.hpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/x86_64/include') 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 -- 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 --- .../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 ++++++ 3 files changed, 57 insertions(+) create mode 100644 arch/x86_64/include/x86_64/memory/kernel_mapper.hpp (limited to 'arch/x86_64/include') 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; }; -- 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 --- .../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 ++++----- 3 files changed, 42 insertions(+), 110 deletions(-) (limited to 'arch/x86_64/include') 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 -- 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 --- .../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 +-- 5 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp (limited to 'arch/x86_64/include') 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 -- 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 --- 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 +++--- 6 files changed, 416 insertions(+), 261 deletions(-) (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index 9af3dc8..b073863 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -1,19 +1,19 @@ -/** - * @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 +//! @file +//! The interface to linker script defined symbols. +//! +//! This header provides declarations for symbols that are defined in the linker script itself. The symbols declared +//! here provide important information, for example the start and end of the kernel image in virtual and physical +//! memory. +//! +//! Any variables defined in this file must not be read themselves, but rather their address shall be taken, yielding a +//! pointer to the memory location the represent. +//! +//! @note The symbols declared in this header are declared using C-language linkage in order to suppress name mangling. +//! +//! @see arch/x86_64/scripts/kernel.ld + +#ifndef TEACHOS_X86_64_BOOT_LD_HPP +#define TEACHOS_X86_64_BOOT_LD_HPP #include @@ -22,55 +22,40 @@ namespace teachos::boot::x86_64 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 - */ + //! The beginning of the kernel image in physical memory + //! + //! This symbol marks the start of the kernel image in physical memory. + //! + //! @see _end_physical extern std::byte _start_physical; - /** - * @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 - */ + //! The first byte after the loaded kernel image. + //! + //! This symbol marks the end of the kernel image in physical memory. + //! + //! @see _start_physical extern std::byte _end_physical; - /** - * @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. - */ + //! The first byte of the loaded kernel image in the virtual address space. + //! + //! This symbol and marks the start of the kernel image in virtual memory. + //! + //! @see _end_virtual extern std::byte _start_virtual; - /** - * @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. - */ + //! The first byte after the loaded kernel image in the virtual address space. + //! + //! This symbol marks the end of the kernel image in virtual memory. + //! + //! @see _start_virtual extern std::byte _end_virtual; - /** - * @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. - */ + //! The first byte of the kernel's virtual address space. + //! + //! This symbol marks beginning of the kernel virtual address space. extern std::byte TEACHOS_VMA; } + } // namespace teachos::boot::x86_64 #endif diff --git a/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp index 0c2254a..c2ad3e7 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 @@ -13,141 +13,248 @@ namespace teachos::cpu::x86_64 { - namespace impl { + //! The assembler templates used to access (r/w) CR0; 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 - }; - - enum struct cr3_flags : std::uint64_t - { - page_level_write_through = 1uz << 0, - page_level_cache_disable = 1uz << 1, - }; - - 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 {}; - }; + //! The assembler templates used to access (r/w) CR2; + constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; + //! The assembler templates used to access (r/w) CR3; + constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; } // namespace impl - using cr0 = impl::control_register; - using cr2 = impl::control_register; - using cr3 = impl::control_register; + //! The flags that can be set on CR0 configuration register. + enum struct cr0_flags : uint64_t + { + //! Enable protected mode. + protection_enable = 1uz << 0, + //! Enable wait-monitoring of the coprocessor after task switching. + monitor_coprocessor = 1uz << 1, + //! Emulate floating point coprocessor. + emulation = 1uz << 2, + //! Marks that a task switch has occurred. + task_switched = 1uz << 3, + //! Marks Intel 387 DX math coprocessor as available + extension_type = 1uz << 4, + //! Numeric error handling mode. + numeric_error = 1uz << 5, + //! Disable writing to read-only marked memory. + write_protect = 1uz << 16, + //! Enable Ring-3 alignment checks + alignment_check = 1uz << 18, + //! Disable write through + not_write_through = 1uz << 29, + //! Disable caching of memory accesses + cache_disable = 1uz << 30, + //! Enable paging + paging = 1uz << 31 + }; + enum struct cr3_flags : std::uint64_t + { + page_level_write_through = 1uz << 0, + page_level_cache_disable = 1uz << 1, + }; } // namespace teachos::cpu::x86_64 namespace kstd::ext { template<> - struct is_bitfield_enum : std::true_type + struct is_bitfield_enum : std::true_type { }; template<> - struct is_bitfield_enum : std::true_type + struct is_bitfield_enum : std::true_type { }; } // namespace kstd::ext +namespace teachos::cpu::x86_64 +{ + //! A mixin for flag-oriented control registers. + //! + //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A + //! control register is flag-oriented, when it's comprises is a bitfield and zero or more additional non-bitfield + //! parts. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct control_register_with_flags + { + }; + + //! @copydoc control_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the control register + //! is an enum. + template + struct control_register_with_flags>> + { + //! The type of the flags used by this control register + using flags = ValueType; + + //! Set one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be set in the control register. + auto static set(ValueType value) -> void + { + auto current = Derived::read(); + current |= value; + Derived::write(current); + } + + //! Clear one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be cleared in the control register. + auto static clear(ValueType value) -> void + { + auto current = Derived::read(); + current &= ~value; + Derived::write(current); + } + }; + + //! A CPU control register. + //! + //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU + //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU + //! in an invalid/undefined state. + template + struct control_register : control_register_with_flags, ValueType> + { + //! Read the current value of the control register. + //! + //! @return The currently set value of the control register. + [[nodiscard]] auto static read() -> ValueType + { + auto value = ValueType{}; + asm volatile((AssemblerTemplates->first) : "=r"(value)); + return value; + } + + //! Write a new value to the control register. + //! + //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value The new value to write to the control register. + auto static write(ValueType value) -> void + { + asm volatile((AssemblerTemplates->second) : : "r"(value)); + } + }; + + //! The value type of the CR3 control register. + //! + //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the + //! page aligned physical address of the root page map, as well as the root paging configuration flags. + struct cr3_value + { + //! Contstruct a 0-value CR3 value. + constexpr cr3_value() = default; + + //! Construct a CR3 value using the given root page map address and flags. + //! + //! @param address The physical address of the root page map + //! @param flags The root configuration flags of the paging system. + constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast(0)) + : m_flags{static_cast(flags)} + , m_address{static_cast(address.raw())} + {} + + //! Extract the physical address of the root page map from this value. + //! + //! @return The physical address of the root page map. + [[nodiscard]] constexpr auto address() const -> memory::physical_address + { + return memory::physical_address{m_address}; + } + + //! Encode the page aligned physical address of the root page map into this value. + //! + //! @param address The page aligned physical address of the root page map. + constexpr auto address(memory::physical_address address) -> void + { + m_address = static_cast(address.raw()); + } + + //! Extract the root paging configuration flags from this value. + //! + //! @return The root paging configuration flags. + [[nodiscard]] constexpr auto flags() const -> cr3_flags + { + return static_cast(m_flags); + } + + //! Encode the root paging configuration flags into this value. + //! + //! @param flags The root paging configuration flags. + constexpr auto flags(cr3_flags flags) -> void + { + m_flags = static_cast(flags); + } + + //! Add the given flags to the current set of encoded root configuration flags of this value. + //! + //! @param flags The root configuration flags to add. + //! @return A reference to this value. + constexpr auto operator|=(cr3_flags flags) -> cr3_value & + { + m_flags |= static_cast(flags); + return *this; + } + + //! Mask the root configuration flags of this value. + //! + //! @param mask The mask to apply to the root configuration flags. + //! @return A reference to this value. + constexpr auto operator&=(cr3_flags mask) -> cr3_value & + { + m_flags &= static_cast(mask); + return *this; + } + + private: + //! Reserved bits. + std::uint64_t : 3; + //! The root paging configuration flags. + std::uint64_t m_flags : 2 {}; + //! Reserved bits. + std::uint64_t : 7; + //! The page aligned physical address of the root page map. + std::uint64_t m_address : 52 {}; + }; + + static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); + + //! Configuration Register 0. + //! + //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. + using cr0 = control_register; + + //! Configuration Register 2. + //! + //! This configuration register holds the memory address the access to which has triggered the most recent page fault. + using cr2 = control_register; + + //! Configuration Register 3. + //! + //! This register holds the configuration of the virtual memory protection configuration. + using cr3 = control_register; + +} // namespace teachos::cpu::x86_64 + #endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp index 2d05010..d7e9491 100644 --- a/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp @@ -35,7 +35,7 @@ namespace teachos::memory::x86_64 auto operator=(buffered_allocator const &) = delete; auto operator=(buffered_allocator &&) = delete; - auto allocate() -> std::optional override + auto allocate() noexcept -> std::optional override { auto found = std::ranges::find_if(m_pool, [](auto const & candidate) { return candidate.has_value(); }); if (found == std::end(m_pool)) 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 6a9c045..6c102b7 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -16,60 +16,103 @@ namespace teachos::memory::x86_64 { - //! A table containing paging entries. + //! A table containing page mapping entries. + //! + //! Page tables exist in a multi-level hierarchy and are used to map pages (virtual memory) onto frames (physical + //! memory). Conceptually, pages represent the data found in a virtual address space, while frames represent their + //! storage. Only a level 1 page table maps an actual page onto a frame. All other page tables on higher levels do not + //! map payload pages, but rather their subordinate page tables. struct page_table { - //! A single page table entry + //! An entry in a page table. + //! + //! A page table entry is a combination of a frame number and a set of flags that determine the properties and + //! access rights to a mapped page. Entries at a higher level in the page hierarchy do not map a page directly, + //! unless that page is marked as huge on the relevant level, but rather map the next lower page table. struct entry { //! Flags marking the state and configuration of an entry. + //! + //! An entry in a page table may have any combination of these flags active at the same time. The final flags of a + //! page are determined as the strictest combination (logical AND) of all flags along the hierarchy. + //! + //! @note This is a bitfield enum as defined by kstd::ext::bitfield_enum. enum struct flags : std::uint64_t { empty = 0, - present = 1uz << 0, - 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, + present = 1uz << 0, //!< The page is mapped. + writable = 1uz << 1, //!< The page is writable. + user_accessible = 1uz << 2, //!< The page is accessible in user mode. + write_through = 1uz << 3, //!< Any writes to the page must immediately hit memory. + disable_cache = 1uz << 4, //!< Any writes to the page must never be cached. + accessed = 1uz << 5, //!< The page was accessed. + dirty = 1uz << 6, //!< The page was written to. + huge_page = 1uz << 7, //!< The page is huge. + global = 1uz << 8, //!< The TLB entry for this page must not be flushed on context switches. + no_execute = 1uz << 63, //!< The data in this page must not be executed. }; + //! Construct an empty entry. entry() = default; - //! Clear this entry, ensuring all information is set to zero, 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; + //! Clear this entry, ensuring all information is set to zero. + //! + //! This effectively marks the page represented by this entry as not present. In addition, it also removes any + //! information about the frame referenced by this entry. + auto clear() noexcept -> void; + + //! Check if the page represented by this entry is present. + //! + //! @note This function does not attempt to walk the page table hierarchy, but only performs a local check. This + //! means, that if the page is not mapped at a lower level, this will not be detected. + //! + //! @return @p true iff. the page is present at this level, @p false otherwise. + [[nodiscard]] auto present() const noexcept -> bool; + + //! Check if the page represented by this entry is a huge page. + //! + //! @note The effective size of the page depends on the level of the page table containing this entry. + //! + //! @return @p true iff. the page is marked as being huge, @p false otherwise. + [[nodiscard]] auto huge() const noexcept -> bool; //! Get all flags present in this entry. - [[nodiscard]] auto all_flags() const -> flags; + //! + //! @return The flags that are currently set on this entry. + [[nodiscard]] auto all_flags() const noexcept -> flags; - //! Set the flags of this entry to the given set. - auto all_flags(flags flags) -> void; + //! Set all flags of this entry. + //! + //! @param flags The flags to apply to this entry. + auto all_flags(flags flags) noexcept -> void; - //! Additively set the given flags in this entry. - auto operator|=(flags rhs) -> entry &; + //! Add the given flags to the flags of this entry. + //! + //! @param rhs The flags to add to this entry's flags. + //! @return A reference to this entry. + auto operator|=(flags rhs) noexcept -> entry &; //! Get the frame number associated with this entry, if the referenced page is present. - [[nodiscard]] auto frame() const -> std::optional; + //! + //! @return an engaged std::optional iff. this entry maps a page, std::nullopt otherwise. + [[nodiscard]] auto frame() const noexcept -> std::optional; - //! Set the entry to reference the given frame with the given flags. - auto frame(struct frame frame, flags flags) -> void; + //! Map this entry. + //! + //! @param frame The frame to map in this entry. + //! @param flags The flags to apply to this entry. + auto frame(struct frame frame, flags flags) noexcept -> void; private: //! A mask to retrieve, or exclude, the frame number from the raw entry. + //! + //! Page table entries in x86_64 are a compacted combination of the relevant flags and the frame number. This mask + //! represents the bits that make up the frame number in an entry. constexpr auto static frame_number_mask{0x000f'ffff'ffff'f000uz}; + //! The raw entry bytes. + //! + //! @see entry::frame_number_mask std::uint64_t m_raw{}; }; @@ -77,13 +120,24 @@ namespace teachos::memory::x86_64 constexpr auto static entry_count{page::size / sizeof(entry)}; //! Get the entry at the given index. + //! + //! @warning This function will panic if the entry index is out of bounds. + //! + //! @param index The index of the desired entry. + //! @return A reference to the entry at the given index. [[nodiscard]] auto operator[](std::size_t index) -> entry &; + + //! @copydoc page_table::operator[] [[nodiscard]] auto operator[](std::size_t index) const -> entry const &; - //! Clear the entire page table, effectively evicting all entries. - auto clear() -> void; + //! Clear the entire page table. + //! + //! This function effectively marks the page table as not mapping any pages. + auto clear() noexcept -> void; //! Check if the page table is empty. + //! + //! @return @p true iff. this page table has no entries marked present, @p false otherwise. [[nodiscard]] auto empty() const noexcept -> bool; private: @@ -91,6 +145,10 @@ namespace teachos::memory::x86_64 }; //! A recursively mapped page table. + //! + //! A page table in which at least one entry maps the same table. Recursive page tables allow for easy access to other + //! tables within the page mapping hierarchy, without having to map them prior to access, through careful construction + //! of linear addresses that pass through the same index multiple times. template requires(Level > 0uz && Level < 5uz) struct recursive_page_table : page_table @@ -99,7 +157,12 @@ namespace teachos::memory::x86_64 constexpr auto static recursive_index = 0776uz; //! Get the next lower lever table. - [[nodiscard]] auto next(this auto && self, std::size_t index) + //! + //! @param self The object type of this object. + //! @param index The index corresponding to the desired page map. + //! @return An engaged std::optional holding a pointer to the next lower page table iff. the next lower page table + //! at the desired index is present, std::nullopt otherwise. + [[nodiscard]] auto next(this auto && self, std::size_t index) noexcept requires(next_level > 1) { return self.next_address(index).transform([](auto address) -> auto { @@ -108,8 +171,10 @@ namespace teachos::memory::x86_64 }); } - //! Get the next lower lever table. - [[nodiscard]] auto next(this auto && self, std::size_t index) + //! @copydoc recursive_page_table::next + //! + //! @note This overload returns a non-hierarchical, or leaf, page table + [[nodiscard]] auto next(this auto && self, std::size_t index) noexcept requires(next_level == 1) { return self.next_address(index).transform([](auto address) -> auto { @@ -119,11 +184,19 @@ namespace teachos::memory::x86_64 } private: + //! The number of address bits used to represent the page index per level. constexpr auto static level_bits = 9; + //! The highest address bit. constexpr auto static high_bit = 48; + //! The number of bits representing the offset into a page. constexpr auto static offset_bits = 12; - [[nodiscard]] auto next_address(std::size_t index) const -> std::optional + //! Calculate the recursive address of the next lower page table. + //! + //! @param index The index of the desired page table. + //! @return An engaged std::optional holding the address of the new lower page table iff. the next lower page table + //! at the desired index is present, std::nullopt otherwise. + [[nodiscard]] auto next_address(std::size_t index) const noexcept -> std::optional { if (auto entry = (*this)[index]; entry.present() && !entry.huge()) { 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 ed95106..75ba120 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -36,7 +36,7 @@ namespace teachos::memory::x86_64 //! //! @warning If the page has not previously been mapped, this function will panic. //! @param page The page to unmap - auto unmap(page) -> void; + auto unmap(page page) -> void; private: paging_root() = default; 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 3ddc8b6..84b7a94 100644 --- a/arch/x86_64/include/x86_64/memory/region_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -12,76 +12,66 @@ namespace teachos::memory::x86_64 { - /** - * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any - * deallocated frames. - */ + //! A simple, memory-region based frame allocator. + //! + //! This frame allocator linearly allocates frames that are in available memory regions. It automatically skips any + //! frames occupied by the kernel image or any bootloader provided data. + //! + //! @note This allocator will never release frames. struct region_allocator final : frame_allocator { struct memory_information { - //! The memory range occupied by the loaded kernel image. This includes all sections that are marked as occupying - //! space in the kernel executable. The internal structure of this area is more described in a more fine-grained - //! manner by the ELF symbol information provided in the Multiboot2 information by the loader. + //! 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. + //! 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. + //! 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; }; - /** - * @brief Constructor. - * - * @param mem_info Structure containing all relevant information to map and allocate memory. - */ - explicit region_allocator(memory_information const & mem_info); + using region = multiboot2::memory_map::region; - /** - * @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() -> std::optional override; + //! Construct a new allocator using the provided memory information + //! + //! @param information The description of the detected memory regions as well as regions that are already occupied. + explicit region_allocator(memory_information const & information); - /** - * @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. - */ + //! @copydoc frame_allocator::allocate + //! + //! @note As long as free frames are available, successive calls to this implementation are guaranteed to yield + //! frames in ascending order. + auto allocate() noexcept -> std::optional override; + + //! @copydoc frame_allocator::release + //! + //! @note This implementation will never actually release any frames. auto release(frame frame) -> void override; private: - /** - * @brief Find the next memory area and write it into current_area. - */ + //! 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 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. + frame m_next_frame; //!< The next available frame. + std::optional m_current_region; //!< The memory region currently used for allocation + multiboot2::memory_map m_memory_map; //!< The boot loader supplied memory map. + frame m_kernel_start; //!< The start of the kernel image in physical memory. + frame m_kernel_end; //!< The end of the kernel image in physical memory. + frame m_multiboot_start; //!< The start of the Multiboot2 information in physical memory. + frame m_multiboot_end; //!< The end of the Multiboot2 information in physical memory. }; } // namespace teachos::memory::x86_64 -- cgit v1.2.3 From cf8d0d899ee17db734ce8ab7ee618333eb1767f2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 18:36:23 +0100 Subject: kapi: finish documentation --- arch/x86_64/include/x86_64/memory/page_table.hpp | 4 ++-- arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/include') 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 6c102b7..3bc2a2b 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -246,7 +246,7 @@ namespace teachos::memory::x86_64 if ((flags & table_flags::user_accessible) == table_flags::empty) { - result |= mapper_flags::supervisor; + result |= mapper_flags::supervisor_only; } return result; @@ -274,7 +274,7 @@ namespace teachos::memory::x86_64 result |= table_flags::disable_cache; } - if ((flags & mapper_flags::supervisor) != mapper_flags::empty) + if ((flags & mapper_flags::supervisor_only) != mapper_flags::empty) { result |= table_flags::user_accessible; } 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 index a66c8d1..dc52065 100644 --- a/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp +++ b/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp @@ -12,7 +12,7 @@ namespace teachos::memory::x86_64 auto map(page page, frame frame, flags flags) -> std::byte * override; auto unmap(page page) -> void override; - auto try_unmap(page page) -> bool override; + auto try_unmap(page page) noexcept -> bool override; private: frame_allocator * m_allocator; -- cgit v1.2.3 From 67267c4d103de2673191c113c1e99e66965aab5c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:16:23 +0100 Subject: x86_64/device_io: simplify implementation --- arch/x86_64/include/x86_64/device_io/port_io.hpp | 155 ++++++++--------------- 1 file changed, 53 insertions(+), 102 deletions(-) (limited to 'arch/x86_64/include') 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 352a4d0..ceabf4a 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 @@ -1,130 +1,81 @@ #ifndef TEACHOS_X86_64_IO_PORT_IO_HPP #define TEACHOS_X86_64_IO_PORT_IO_HPP +#include #include #include +#include #include namespace teachos::io::x86_64 { - /** - * @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. - */ + + //! An I/O port of a given size at a given address. + //! + //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte to + //! double-word sized transfers. + //! + //! @tparam Address The address (port number) of the I/O port. + //! @tparam Size The size (in bytes) of the I/O port. template + requires(Size == 1 || Size == 2 || Size == 4) 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 = + //! The type of data available for reading and writing through this port. + using value_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) + //! Read from the I/O port. + //! + //! @return The data read from the I/O port. + auto static read() noexcept -> value_type { - asm volatile("mov %[port], %%dx\n" - "mov %[data], %%al\n" - "out %%al, %%dx\n" - : - : [port] "i"(Address), [data] "im"(data) - : "dx", "al"); + auto data = value_type{}; + asm volatile((read_code[asm_template_index]) + : [data] "=m"(data) + : [port] "i"(Address) + : "dx", (data_register[asm_template_index])); + return data; } - /** - * @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) + //! Write data to the I/O port. + //! + //! @param data The data to write to the I/O port. + auto static write(value_type data) noexcept -> void { - asm volatile("mov %[port], %%dx\n" - "mov %[data], %%ax\n" - "out %%ax, %%dx\n" + asm volatile((write_code[asm_template_index]) : : [port] "i"(Address), [data] "im"(data) - : "dx", "ax"); + : "dx", (data_register[asm_template_index])); } - /** - * @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"); - } + private: + //! The index into the assembly template and register arrays. + //! + //! This index is used to select the correct assembly templates for the given operation (read or write), as well as + //! the clobbered data register, from the relevant template arrays. + constexpr auto static asm_template_index = Size / 2; - /** - * @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; - } + //! The assembly templates used for reading from an I/O port. + constexpr auto static read_code = std::array{ + std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"}, + std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"}, + std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"}, + }; - /** - * @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; - } + //! The assembly templates used for writing to an I/O port. + constexpr auto static write_code = std::array{ + std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%al, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%ax, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%eax, %%dx"}, + }; - /** - * @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; - } + //! The registers clobbered by the I/O operation. + constexpr auto static data_register = std::array{ + std::string_view{"al"}, + std::string_view{"ax"}, + std::string_view{"eax"}, + }; }; } // namespace teachos::io::x86_64 -- cgit v1.2.3 From f8c3c91e81f434c26dd84e5047a4420e8fb40534 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:28:36 +0100 Subject: x86_64/device_io: switch to typed port io. --- arch/x86_64/include/x86_64/device_io/port_io.hpp | 22 +++++++++++++++++----- arch/x86_64/include/x86_64/vga/crtc.hpp | 4 ++-- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/include') 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 ceabf4a..9f115eb 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 @@ -2,6 +2,7 @@ #define TEACHOS_X86_64_IO_PORT_IO_HPP #include +#include #include #include #include @@ -10,6 +11,16 @@ namespace teachos::io::x86_64 { + //! The requirements imposed on a type usable for port I/O. + template + concept port_io_type = requires { + requires sizeof(ValueType) == 1 || sizeof(ValueType) == 2 || sizeof(ValueType) == 4; + requires std::default_initializable; + std::bit_cast( + std::conditional_t>{}); + }; + //! An I/O port of a given size at a given address. //! //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte to @@ -17,13 +28,14 @@ namespace teachos::io::x86_64 //! //! @tparam Address The address (port number) of the I/O port. //! @tparam Size The size (in bytes) of the I/O port. - template - requires(Size == 1 || Size == 2 || Size == 4) + template struct port { //! The type of data available for reading and writing through this port. - using value_type = - std::conditional_t>; + using value_type = ValueType; + + //! The size of the I/O port + constexpr auto static size = sizeof(value_type); //! Read from the I/O port. //! @@ -54,7 +66,7 @@ namespace teachos::io::x86_64 //! //! This index is used to select the correct assembly templates for the given operation (read or write), as well as //! the clobbered data register, from the relevant template arrays. - constexpr auto static asm_template_index = Size / 2; + constexpr auto static asm_template_index = size / 2; //! The assembly templates used for reading from an I/O port. constexpr auto static read_code = std::array{ diff --git a/arch/x86_64/include/x86_64/vga/crtc.hpp b/arch/x86_64/include/x86_64/vga/crtc.hpp index 8bdc12d..b2c8028 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>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) + using address = io::x86_64::port<0x3d4, std::byte>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) /** * @brief The data port of the CRT Controller. */ - using data = io::x86_64::port<0x3d5, 1>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) + using data = io::x86_64::port<0x3d5, std::byte>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) namespace registers { -- cgit v1.2.3 From d89dd14c4492144d54ad755932b3e2c89a17bf74 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:50:40 +0100 Subject: x86_64/device_io: split port read/write features --- arch/x86_64/include/x86_64/device_io/port_io.hpp | 94 +++++++++++++----------- arch/x86_64/include/x86_64/vga/crtc.hpp | 8 +- 2 files changed, 56 insertions(+), 46 deletions(-) (limited to 'arch/x86_64/include') 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 9f115eb..c3e5271 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 @@ -21,73 +21,79 @@ namespace teachos::io::x86_64 std::conditional_t>{}); }; - //! An I/O port of a given size at a given address. - //! - //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte to - //! double-word sized transfers. - //! - //! @tparam Address The address (port number) of the I/O port. - //! @tparam Size The size (in bytes) of the I/O port. - template - struct port + template + struct port_read { - //! The type of data available for reading and writing through this port. - using value_type = ValueType; - - //! The size of the I/O port - constexpr auto static size = sizeof(value_type); - //! Read from the I/O port. //! //! @return The data read from the I/O port. - auto static read() noexcept -> value_type + auto static read() noexcept { - auto data = value_type{}; - asm volatile((read_code[asm_template_index]) + auto data = typename Derived::value_type{}; + asm volatile((code[Derived::size / 2]) : [data] "=m"(data) - : [port] "i"(Address) - : "dx", (data_register[asm_template_index])); + : [port] "i"(Derived::size) + : "dx", (Derived::data_register)); return data; } + private: + //! The assembly templates used for reading from an I/O port. + constexpr auto static code = std::array{ + std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"}, + std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"}, + std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"}, + }; + }; + + template + struct port_write + { //! Write data to the I/O port. //! //! @param data The data to write to the I/O port. - auto static write(value_type data) noexcept -> void + auto static write(std::same_as auto data) noexcept -> void { - asm volatile((write_code[asm_template_index]) + asm volatile((code[Derived::size / 2]) : - : [port] "i"(Address), [data] "im"(data) - : "dx", (data_register[asm_template_index])); + : [port] "i"(Derived::address), [data] "im"(data) + : "dx", (Derived::data_register)); } private: - //! The index into the assembly template and register arrays. - //! - //! This index is used to select the correct assembly templates for the given operation (read or write), as well as - //! the clobbered data register, from the relevant template arrays. - constexpr auto static asm_template_index = size / 2; - - //! The assembly templates used for reading from an I/O port. - constexpr auto static read_code = std::array{ - std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"}, - std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"}, - std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"}, - }; - //! The assembly templates used for writing to an I/O port. - constexpr auto static write_code = std::array{ + constexpr auto static code = std::array{ std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%al, %%dx"}, std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%ax, %%dx"}, std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%eax, %%dx"}, }; + }; - //! The registers clobbered by the I/O operation. - constexpr auto static data_register = std::array{ - std::string_view{"al"}, - std::string_view{"ax"}, - std::string_view{"eax"}, - }; + //! An I/O port of a given size at a given address. + //! + //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte + //! to double-word sized transfers. + //! + //! @tparam Address The address (port number) of the I/O port. + //! @tparam Size The size (in bytes) of the I/O port. + //! @tparam Features The features (readable, writeable) + template typename... Features> + requires(sizeof...(Features) > 0) + struct port : Features>... + { + //! The type of the data of this port. + using value_type = ValueType; + + //! The address of this I/O port. + constexpr auto static address = Address; + + //! The size of this I/O port. + constexpr auto static size = sizeof(value_type); + + //! The register clobbered by the I/O operation. + constexpr auto static data_register = size == 1 ? std::string_view{"al"} + : size == 2 ? std::string_view{"ax"} + : std::string_view{"eax"}; }; } // namespace teachos::io::x86_64 diff --git a/arch/x86_64/include/x86_64/vga/crtc.hpp b/arch/x86_64/include/x86_64/vga/crtc.hpp index b2c8028..d4b4f51 100644 --- a/arch/x86_64/include/x86_64/vga/crtc.hpp +++ b/arch/x86_64/include/x86_64/vga/crtc.hpp @@ -7,15 +7,19 @@ namespace teachos::vga::x86_64::crtc { + namespace io = io::x86_64; + /** * @brief The address port of the CRT Controller. */ - using address = io::x86_64::port<0x3d4, std::byte>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + using address = io::port<0x3d4, std::byte, io::port_write>; /** * @brief The data port of the CRT Controller. */ - using data = io::x86_64::port<0x3d5, std::byte>; // NOLINT(cppcoreguidelines-avoid-magic-numbers) + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + using data = io::port<0x3d5, std::byte, io::port_read, io::port_write>; namespace registers { -- cgit v1.2.3 From 822b17b852cdc8933881132dd7b862ee74117973 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:52:38 +0100 Subject: x86_64/cpu: update documentation and structure --- .../include/x86_64/cpu/impl/control_registers.hpp | 5 +- .../x86_64/cpu/impl/model_specific_register.hpp | 195 +++++++++++++-------- 2 files changed, 127 insertions(+), 73 deletions(-) (limited to 'arch/x86_64/include') 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 c2ad3e7..1f8c690 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,7 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP #define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP -// IWYU pragma: private +// IWYU pragma: private, include "x86_64/cpu/registers.hpp" #include "kapi/memory/address.hpp" @@ -77,8 +77,7 @@ namespace teachos::cpu::x86_64 //! A mixin for flag-oriented control registers. //! //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A - //! control register is flag-oriented, when it's comprises is a bitfield and zero or more additional non-bitfield - //! parts. + //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. //! //! @tparam Derived The class deriving from this mixin. //! @tparam ValueType The value type of the class deriving from this mixin. 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 ff2c8ad..080b280 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,7 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP #define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP -// IWYU pragma: private +// IWYU pragma: private, include "x86_64/cpu/registers.hpp" #include @@ -11,75 +11,19 @@ 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, - }; - - } // namespace impl - - using i32_efer = impl::model_specific_register; + //! The flags of the IA32_EFER (Extended Features Enable Register) MSR. + enum struct ia32_efer_flags : std::uint64_t + { + //! Enable the syscall and sysret instructions. + syscall_enable = 1uz << 0, + //! Enable IA-32e mode operation. + ia32e_mode_enable = 1uz << 8, + //! Indicates IA-32e mode is active (read-only) + ia32e_mode_active = 1uz << 10, + //! Enable the use of the NX page table bit. + execute_disable_bit_enable = 1uz << 11, + }; } // namespace teachos::cpu::x86_64 @@ -87,10 +31,121 @@ namespace kstd::ext { template<> - struct is_bitfield_enum : std::true_type + struct is_bitfield_enum : std::true_type { }; } // namespace kstd::ext +namespace teachos::cpu::x86_64 +{ + //! The MSR number for the IA32_EFER MSR + constexpr auto ia32_efer_number = 0xC000'0080u; + + //! A mixin for flag-oriented model specific registers. + //! + //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific + //! register is flag-oriented, if it comprises a single field of bitfield. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct model_specific_register_with_flags + { + }; + + //! @copydoc model_specific_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the model specific + //! register is a bitfield enum. + template + struct model_specific_register_with_flags>> + { + //! The of the flags used by this model specific register. + using flags = ValueType; + + //! Set one or more flags in this model specific register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param flag One or a combination of flags to be set in the model specific register. + auto static set(flags flag) -> void + { + auto current = Derived::read(); + current |= flag; + Derived::write(current); + } + + //! Clear one or more flags in this model specific register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param flag One or a combination of flags to be cleared in the model specific register. + auto static clear(flags flag) -> void + { + auto current = Derived::read(); + current &= ~flag; + Derived::write(current); + } + + //! Test one or more flags in this model specific register + //! + //! @param flag One or a combination of flags to test for. + auto test(flags flag) -> flags + { + return Derived::read() & flag; + } + }; + + //! A model specific register (MSR) + //! + //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations. + //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in + //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in + //! an invalid/undefined state. + //! + //! @tparam Number The register number of this MSR + //! @tparam ValueType The value type of this MSR + template + struct model_specific_register + : model_specific_register_with_flags, ValueType> + { + //! A raw MSR value, comprising two halfs. + //! + //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs. + struct raw_value + { + std::uint32_t low_half; //!< The lower half of the register value + std::uint32_t high_half; //!< The upper half of the register value + }; + + //! Read the current value of this MSR. + //! + //! @return The current value of this MSR. + auto static read() -> ValueType + { + auto raw = raw_value{}; + asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); + return static_cast(std::bit_cast(raw)); + } + + //! Write a new value to this MSR. + //! + //! @param value The new value for this MSR. + auto static write(ValueType value) -> void + { + auto raw = std::bit_cast(static_cast(value)); + asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); + } + }; + + //! The I32_EFER (Extended Feature Enable Register) MSR + using i32_efer = model_specific_register; + +} // namespace teachos::cpu::x86_64 + #endif \ No newline at end of file -- cgit v1.2.3 From 6fdfe22f75c7202eee84b9b89f6abd5dbc60fedc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:54:22 +0100 Subject: x86_64/cpu: flatten file hierarchy --- .../include/x86_64/cpu/control_registers.hpp | 259 +++++++++++++++++++++ .../include/x86_64/cpu/impl/control_registers.hpp | 259 --------------------- .../x86_64/cpu/impl/model_specific_register.hpp | 151 ------------ .../include/x86_64/cpu/model_specific_register.hpp | 151 ++++++++++++ arch/x86_64/include/x86_64/cpu/registers.hpp | 4 +- 5 files changed, 412 insertions(+), 412 deletions(-) create mode 100644 arch/x86_64/include/x86_64/cpu/control_registers.hpp delete mode 100644 arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp delete mode 100644 arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp create mode 100644 arch/x86_64/include/x86_64/cpu/model_specific_register.hpp (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/x86_64/cpu/control_registers.hpp b/arch/x86_64/include/x86_64/cpu/control_registers.hpp new file mode 100644 index 0000000..1f8c690 --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/control_registers.hpp @@ -0,0 +1,259 @@ +#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP + +// IWYU pragma: private, include "x86_64/cpu/registers.hpp" + +#include "kapi/memory/address.hpp" + +#include + +#include +#include +#include + +namespace teachos::cpu::x86_64 +{ + namespace impl + { + //! The assembler templates used to access (r/w) CR0; + constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; + + //! The assembler templates used to access (r/w) CR2; + constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; + + //! The assembler templates used to access (r/w) CR3; + constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; + } // namespace impl + + //! The flags that can be set on CR0 configuration register. + enum struct cr0_flags : uint64_t + { + //! Enable protected mode. + protection_enable = 1uz << 0, + //! Enable wait-monitoring of the coprocessor after task switching. + monitor_coprocessor = 1uz << 1, + //! Emulate floating point coprocessor. + emulation = 1uz << 2, + //! Marks that a task switch has occurred. + task_switched = 1uz << 3, + //! Marks Intel 387 DX math coprocessor as available + extension_type = 1uz << 4, + //! Numeric error handling mode. + numeric_error = 1uz << 5, + //! Disable writing to read-only marked memory. + write_protect = 1uz << 16, + //! Enable Ring-3 alignment checks + alignment_check = 1uz << 18, + //! Disable write through + not_write_through = 1uz << 29, + //! Disable caching of memory accesses + cache_disable = 1uz << 30, + //! Enable paging + paging = 1uz << 31 + }; + + enum struct cr3_flags : std::uint64_t + { + page_level_write_through = 1uz << 0, + page_level_cache_disable = 1uz << 1, + }; +} // namespace teachos::cpu::x86_64 + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; + + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + +namespace teachos::cpu::x86_64 +{ + //! A mixin for flag-oriented control registers. + //! + //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A + //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct control_register_with_flags + { + }; + + //! @copydoc control_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the control register + //! is an enum. + template + struct control_register_with_flags>> + { + //! The type of the flags used by this control register + using flags = ValueType; + + //! Set one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be set in the control register. + auto static set(ValueType value) -> void + { + auto current = Derived::read(); + current |= value; + Derived::write(current); + } + + //! Clear one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be cleared in the control register. + auto static clear(ValueType value) -> void + { + auto current = Derived::read(); + current &= ~value; + Derived::write(current); + } + }; + + //! A CPU control register. + //! + //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU + //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU + //! in an invalid/undefined state. + template + struct control_register : control_register_with_flags, ValueType> + { + //! Read the current value of the control register. + //! + //! @return The currently set value of the control register. + [[nodiscard]] auto static read() -> ValueType + { + auto value = ValueType{}; + asm volatile((AssemblerTemplates->first) : "=r"(value)); + return value; + } + + //! Write a new value to the control register. + //! + //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value The new value to write to the control register. + auto static write(ValueType value) -> void + { + asm volatile((AssemblerTemplates->second) : : "r"(value)); + } + }; + + //! The value type of the CR3 control register. + //! + //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the + //! page aligned physical address of the root page map, as well as the root paging configuration flags. + struct cr3_value + { + //! Contstruct a 0-value CR3 value. + constexpr cr3_value() = default; + + //! Construct a CR3 value using the given root page map address and flags. + //! + //! @param address The physical address of the root page map + //! @param flags The root configuration flags of the paging system. + constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast(0)) + : m_flags{static_cast(flags)} + , m_address{static_cast(address.raw())} + {} + + //! Extract the physical address of the root page map from this value. + //! + //! @return The physical address of the root page map. + [[nodiscard]] constexpr auto address() const -> memory::physical_address + { + return memory::physical_address{m_address}; + } + + //! Encode the page aligned physical address of the root page map into this value. + //! + //! @param address The page aligned physical address of the root page map. + constexpr auto address(memory::physical_address address) -> void + { + m_address = static_cast(address.raw()); + } + + //! Extract the root paging configuration flags from this value. + //! + //! @return The root paging configuration flags. + [[nodiscard]] constexpr auto flags() const -> cr3_flags + { + return static_cast(m_flags); + } + + //! Encode the root paging configuration flags into this value. + //! + //! @param flags The root paging configuration flags. + constexpr auto flags(cr3_flags flags) -> void + { + m_flags = static_cast(flags); + } + + //! Add the given flags to the current set of encoded root configuration flags of this value. + //! + //! @param flags The root configuration flags to add. + //! @return A reference to this value. + constexpr auto operator|=(cr3_flags flags) -> cr3_value & + { + m_flags |= static_cast(flags); + return *this; + } + + //! Mask the root configuration flags of this value. + //! + //! @param mask The mask to apply to the root configuration flags. + //! @return A reference to this value. + constexpr auto operator&=(cr3_flags mask) -> cr3_value & + { + m_flags &= static_cast(mask); + return *this; + } + + private: + //! Reserved bits. + std::uint64_t : 3; + //! The root paging configuration flags. + std::uint64_t m_flags : 2 {}; + //! Reserved bits. + std::uint64_t : 7; + //! The page aligned physical address of the root page map. + std::uint64_t m_address : 52 {}; + }; + + static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); + + //! Configuration Register 0. + //! + //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. + using cr0 = control_register; + + //! Configuration Register 2. + //! + //! This configuration register holds the memory address the access to which has triggered the most recent page fault. + using cr2 = control_register; + + //! Configuration Register 3. + //! + //! This register holds the configuration of the virtual memory protection configuration. + using cr3 = control_register; + +} // namespace teachos::cpu::x86_64 + +#endif \ No newline at end of file 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 deleted file mode 100644 index 1f8c690..0000000 --- a/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP -#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP - -// IWYU pragma: private, include "x86_64/cpu/registers.hpp" - -#include "kapi/memory/address.hpp" - -#include - -#include -#include -#include - -namespace teachos::cpu::x86_64 -{ - namespace impl - { - //! The assembler templates used to access (r/w) CR0; - constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; - - //! The assembler templates used to access (r/w) CR2; - constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; - - //! The assembler templates used to access (r/w) CR3; - constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; - } // namespace impl - - //! The flags that can be set on CR0 configuration register. - enum struct cr0_flags : uint64_t - { - //! Enable protected mode. - protection_enable = 1uz << 0, - //! Enable wait-monitoring of the coprocessor after task switching. - monitor_coprocessor = 1uz << 1, - //! Emulate floating point coprocessor. - emulation = 1uz << 2, - //! Marks that a task switch has occurred. - task_switched = 1uz << 3, - //! Marks Intel 387 DX math coprocessor as available - extension_type = 1uz << 4, - //! Numeric error handling mode. - numeric_error = 1uz << 5, - //! Disable writing to read-only marked memory. - write_protect = 1uz << 16, - //! Enable Ring-3 alignment checks - alignment_check = 1uz << 18, - //! Disable write through - not_write_through = 1uz << 29, - //! Disable caching of memory accesses - cache_disable = 1uz << 30, - //! Enable paging - paging = 1uz << 31 - }; - - enum struct cr3_flags : std::uint64_t - { - page_level_write_through = 1uz << 0, - page_level_cache_disable = 1uz << 1, - }; -} // namespace teachos::cpu::x86_64 - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; - - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -namespace teachos::cpu::x86_64 -{ - //! A mixin for flag-oriented control registers. - //! - //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A - //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct control_register_with_flags - { - }; - - //! @copydoc control_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the control register - //! is an enum. - template - struct control_register_with_flags>> - { - //! The type of the flags used by this control register - using flags = ValueType; - - //! Set one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be set in the control register. - auto static set(ValueType value) -> void - { - auto current = Derived::read(); - current |= value; - Derived::write(current); - } - - //! Clear one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be cleared in the control register. - auto static clear(ValueType value) -> void - { - auto current = Derived::read(); - current &= ~value; - Derived::write(current); - } - }; - - //! A CPU control register. - //! - //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU - //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU - //! in an invalid/undefined state. - template - struct control_register : control_register_with_flags, ValueType> - { - //! Read the current value of the control register. - //! - //! @return The currently set value of the control register. - [[nodiscard]] auto static read() -> ValueType - { - auto value = ValueType{}; - asm volatile((AssemblerTemplates->first) : "=r"(value)); - return value; - } - - //! Write a new value to the control register. - //! - //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value The new value to write to the control register. - auto static write(ValueType value) -> void - { - asm volatile((AssemblerTemplates->second) : : "r"(value)); - } - }; - - //! The value type of the CR3 control register. - //! - //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the - //! page aligned physical address of the root page map, as well as the root paging configuration flags. - struct cr3_value - { - //! Contstruct a 0-value CR3 value. - constexpr cr3_value() = default; - - //! Construct a CR3 value using the given root page map address and flags. - //! - //! @param address The physical address of the root page map - //! @param flags The root configuration flags of the paging system. - constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast(0)) - : m_flags{static_cast(flags)} - , m_address{static_cast(address.raw())} - {} - - //! Extract the physical address of the root page map from this value. - //! - //! @return The physical address of the root page map. - [[nodiscard]] constexpr auto address() const -> memory::physical_address - { - return memory::physical_address{m_address}; - } - - //! Encode the page aligned physical address of the root page map into this value. - //! - //! @param address The page aligned physical address of the root page map. - constexpr auto address(memory::physical_address address) -> void - { - m_address = static_cast(address.raw()); - } - - //! Extract the root paging configuration flags from this value. - //! - //! @return The root paging configuration flags. - [[nodiscard]] constexpr auto flags() const -> cr3_flags - { - return static_cast(m_flags); - } - - //! Encode the root paging configuration flags into this value. - //! - //! @param flags The root paging configuration flags. - constexpr auto flags(cr3_flags flags) -> void - { - m_flags = static_cast(flags); - } - - //! Add the given flags to the current set of encoded root configuration flags of this value. - //! - //! @param flags The root configuration flags to add. - //! @return A reference to this value. - constexpr auto operator|=(cr3_flags flags) -> cr3_value & - { - m_flags |= static_cast(flags); - return *this; - } - - //! Mask the root configuration flags of this value. - //! - //! @param mask The mask to apply to the root configuration flags. - //! @return A reference to this value. - constexpr auto operator&=(cr3_flags mask) -> cr3_value & - { - m_flags &= static_cast(mask); - return *this; - } - - private: - //! Reserved bits. - std::uint64_t : 3; - //! The root paging configuration flags. - std::uint64_t m_flags : 2 {}; - //! Reserved bits. - std::uint64_t : 7; - //! The page aligned physical address of the root page map. - std::uint64_t m_address : 52 {}; - }; - - static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); - - //! Configuration Register 0. - //! - //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. - using cr0 = control_register; - - //! Configuration Register 2. - //! - //! This configuration register holds the memory address the access to which has triggered the most recent page fault. - using cr2 = control_register; - - //! Configuration Register 3. - //! - //! This register holds the configuration of the virtual memory protection configuration. - using cr3 = control_register; - -} // namespace teachos::cpu::x86_64 - -#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 deleted file mode 100644 index 080b280..0000000 --- a/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP -#define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP - -// IWYU pragma: private, include "x86_64/cpu/registers.hpp" - -#include - -#include -#include -#include - -namespace teachos::cpu::x86_64 -{ - - //! The flags of the IA32_EFER (Extended Features Enable Register) MSR. - enum struct ia32_efer_flags : std::uint64_t - { - //! Enable the syscall and sysret instructions. - syscall_enable = 1uz << 0, - //! Enable IA-32e mode operation. - ia32e_mode_enable = 1uz << 8, - //! Indicates IA-32e mode is active (read-only) - ia32e_mode_active = 1uz << 10, - //! Enable the use of the NX page table bit. - execute_disable_bit_enable = 1uz << 11, - }; - -} // namespace teachos::cpu::x86_64 - -namespace kstd::ext -{ - - template<> - struct is_bitfield_enum : std::true_type - { - }; - -} // namespace kstd::ext - -namespace teachos::cpu::x86_64 -{ - //! The MSR number for the IA32_EFER MSR - constexpr auto ia32_efer_number = 0xC000'0080u; - - //! A mixin for flag-oriented model specific registers. - //! - //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific - //! register is flag-oriented, if it comprises a single field of bitfield. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct model_specific_register_with_flags - { - }; - - //! @copydoc model_specific_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the model specific - //! register is a bitfield enum. - template - struct model_specific_register_with_flags>> - { - //! The of the flags used by this model specific register. - using flags = ValueType; - - //! Set one or more flags in this model specific register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param flag One or a combination of flags to be set in the model specific register. - auto static set(flags flag) -> void - { - auto current = Derived::read(); - current |= flag; - Derived::write(current); - } - - //! Clear one or more flags in this model specific register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param flag One or a combination of flags to be cleared in the model specific register. - auto static clear(flags flag) -> void - { - auto current = Derived::read(); - current &= ~flag; - Derived::write(current); - } - - //! Test one or more flags in this model specific register - //! - //! @param flag One or a combination of flags to test for. - auto test(flags flag) -> flags - { - return Derived::read() & flag; - } - }; - - //! A model specific register (MSR) - //! - //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations. - //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in - //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in - //! an invalid/undefined state. - //! - //! @tparam Number The register number of this MSR - //! @tparam ValueType The value type of this MSR - template - struct model_specific_register - : model_specific_register_with_flags, ValueType> - { - //! A raw MSR value, comprising two halfs. - //! - //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs. - struct raw_value - { - std::uint32_t low_half; //!< The lower half of the register value - std::uint32_t high_half; //!< The upper half of the register value - }; - - //! Read the current value of this MSR. - //! - //! @return The current value of this MSR. - auto static read() -> ValueType - { - auto raw = raw_value{}; - asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); - return static_cast(std::bit_cast(raw)); - } - - //! Write a new value to this MSR. - //! - //! @param value The new value for this MSR. - auto static write(ValueType value) -> void - { - auto raw = std::bit_cast(static_cast(value)); - asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); - } - }; - - //! The I32_EFER (Extended Feature Enable Register) MSR - using i32_efer = 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/model_specific_register.hpp b/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp new file mode 100644 index 0000000..080b280 --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp @@ -0,0 +1,151 @@ +#ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP +#define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP + +// IWYU pragma: private, include "x86_64/cpu/registers.hpp" + +#include + +#include +#include +#include + +namespace teachos::cpu::x86_64 +{ + + //! The flags of the IA32_EFER (Extended Features Enable Register) MSR. + enum struct ia32_efer_flags : std::uint64_t + { + //! Enable the syscall and sysret instructions. + syscall_enable = 1uz << 0, + //! Enable IA-32e mode operation. + ia32e_mode_enable = 1uz << 8, + //! Indicates IA-32e mode is active (read-only) + ia32e_mode_active = 1uz << 10, + //! Enable the use of the NX page table bit. + execute_disable_bit_enable = 1uz << 11, + }; + +} // namespace teachos::cpu::x86_64 + +namespace kstd::ext +{ + + template<> + struct is_bitfield_enum : std::true_type + { + }; + +} // namespace kstd::ext + +namespace teachos::cpu::x86_64 +{ + //! The MSR number for the IA32_EFER MSR + constexpr auto ia32_efer_number = 0xC000'0080u; + + //! A mixin for flag-oriented model specific registers. + //! + //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific + //! register is flag-oriented, if it comprises a single field of bitfield. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct model_specific_register_with_flags + { + }; + + //! @copydoc model_specific_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the model specific + //! register is a bitfield enum. + template + struct model_specific_register_with_flags>> + { + //! The of the flags used by this model specific register. + using flags = ValueType; + + //! Set one or more flags in this model specific register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param flag One or a combination of flags to be set in the model specific register. + auto static set(flags flag) -> void + { + auto current = Derived::read(); + current |= flag; + Derived::write(current); + } + + //! Clear one or more flags in this model specific register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param flag One or a combination of flags to be cleared in the model specific register. + auto static clear(flags flag) -> void + { + auto current = Derived::read(); + current &= ~flag; + Derived::write(current); + } + + //! Test one or more flags in this model specific register + //! + //! @param flag One or a combination of flags to test for. + auto test(flags flag) -> flags + { + return Derived::read() & flag; + } + }; + + //! A model specific register (MSR) + //! + //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations. + //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in + //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in + //! an invalid/undefined state. + //! + //! @tparam Number The register number of this MSR + //! @tparam ValueType The value type of this MSR + template + struct model_specific_register + : model_specific_register_with_flags, ValueType> + { + //! A raw MSR value, comprising two halfs. + //! + //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs. + struct raw_value + { + std::uint32_t low_half; //!< The lower half of the register value + std::uint32_t high_half; //!< The upper half of the register value + }; + + //! Read the current value of this MSR. + //! + //! @return The current value of this MSR. + auto static read() -> ValueType + { + auto raw = raw_value{}; + asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); + return static_cast(std::bit_cast(raw)); + } + + //! Write a new value to this MSR. + //! + //! @param value The new value for this MSR. + auto static write(ValueType value) -> void + { + auto raw = std::bit_cast(static_cast(value)); + asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); + } + }; + + //! The I32_EFER (Extended Feature Enable Register) MSR + using i32_efer = 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 97cba19..cb56270 100644 --- a/arch/x86_64/include/x86_64/cpu/registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -1,7 +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/model_specific_register.hpp" // IWYU pragma: export +#include "x86_64/cpu/control_registers.hpp" // IWYU pragma: export +#include "x86_64/cpu/model_specific_register.hpp" // IWYU pragma: export #endif \ No newline at end of file -- cgit v1.2.3 From 0a2c2c408d8fda248d56df349b4c9f9cc5e8bade Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:56:11 +0100 Subject: x86_64/cpu: move register definitions --- .../x86_64/include/x86_64/cpu/control_register.hpp | 244 +++++++++++++++++++ .../include/x86_64/cpu/control_registers.hpp | 259 --------------------- .../include/x86_64/cpu/model_specific_register.hpp | 3 - arch/x86_64/include/x86_64/cpu/registers.hpp | 25 +- 4 files changed, 268 insertions(+), 263 deletions(-) create mode 100644 arch/x86_64/include/x86_64/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/x86_64/cpu/control_registers.hpp (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/x86_64/cpu/control_register.hpp b/arch/x86_64/include/x86_64/cpu/control_register.hpp new file mode 100644 index 0000000..35ffcae --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/control_register.hpp @@ -0,0 +1,244 @@ +#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP + +// IWYU pragma: private, include "x86_64/cpu/registers.hpp" + +#include "kapi/memory/address.hpp" + +#include + +#include +#include +#include + +namespace teachos::cpu::x86_64 +{ + namespace impl + { + //! The assembler templates used to access (r/w) CR0; + constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; + + //! The assembler templates used to access (r/w) CR2; + constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; + + //! The assembler templates used to access (r/w) CR3; + constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; + } // namespace impl + + //! The flags that can be set on CR0 configuration register. + enum struct cr0_flags : uint64_t + { + //! Enable protected mode. + protection_enable = 1uz << 0, + //! Enable wait-monitoring of the coprocessor after task switching. + monitor_coprocessor = 1uz << 1, + //! Emulate floating point coprocessor. + emulation = 1uz << 2, + //! Marks that a task switch has occurred. + task_switched = 1uz << 3, + //! Marks Intel 387 DX math coprocessor as available + extension_type = 1uz << 4, + //! Numeric error handling mode. + numeric_error = 1uz << 5, + //! Disable writing to read-only marked memory. + write_protect = 1uz << 16, + //! Enable Ring-3 alignment checks + alignment_check = 1uz << 18, + //! Disable write through + not_write_through = 1uz << 29, + //! Disable caching of memory accesses + cache_disable = 1uz << 30, + //! Enable paging + paging = 1uz << 31 + }; + + enum struct cr3_flags : std::uint64_t + { + page_level_write_through = 1uz << 0, + page_level_cache_disable = 1uz << 1, + }; +} // namespace teachos::cpu::x86_64 + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; + + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + +namespace teachos::cpu::x86_64 +{ + //! A mixin for flag-oriented control registers. + //! + //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A + //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct control_register_with_flags + { + }; + + //! @copydoc control_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the control register + //! is an enum. + template + struct control_register_with_flags>> + { + //! The type of the flags used by this control register + using flags = ValueType; + + //! Set one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be set in the control register. + auto static set(ValueType value) -> void + { + auto current = Derived::read(); + current |= value; + Derived::write(current); + } + + //! Clear one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be cleared in the control register. + auto static clear(ValueType value) -> void + { + auto current = Derived::read(); + current &= ~value; + Derived::write(current); + } + }; + + //! A CPU control register. + //! + //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU + //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU + //! in an invalid/undefined state. + template + struct control_register : control_register_with_flags, ValueType> + { + //! Read the current value of the control register. + //! + //! @return The currently set value of the control register. + [[nodiscard]] auto static read() -> ValueType + { + auto value = ValueType{}; + asm volatile((AssemblerTemplates->first) : "=r"(value)); + return value; + } + + //! Write a new value to the control register. + //! + //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value The new value to write to the control register. + auto static write(ValueType value) -> void + { + asm volatile((AssemblerTemplates->second) : : "r"(value)); + } + }; + + //! The value type of the CR3 control register. + //! + //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the + //! page aligned physical address of the root page map, as well as the root paging configuration flags. + struct cr3_value + { + //! Contstruct a 0-value CR3 value. + constexpr cr3_value() = default; + + //! Construct a CR3 value using the given root page map address and flags. + //! + //! @param address The physical address of the root page map + //! @param flags The root configuration flags of the paging system. + constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast(0)) + : m_flags{static_cast(flags)} + , m_address{static_cast(address.raw())} + {} + + //! Extract the physical address of the root page map from this value. + //! + //! @return The physical address of the root page map. + [[nodiscard]] constexpr auto address() const -> memory::physical_address + { + return memory::physical_address{m_address}; + } + + //! Encode the page aligned physical address of the root page map into this value. + //! + //! @param address The page aligned physical address of the root page map. + constexpr auto address(memory::physical_address address) -> void + { + m_address = static_cast(address.raw()); + } + + //! Extract the root paging configuration flags from this value. + //! + //! @return The root paging configuration flags. + [[nodiscard]] constexpr auto flags() const -> cr3_flags + { + return static_cast(m_flags); + } + + //! Encode the root paging configuration flags into this value. + //! + //! @param flags The root paging configuration flags. + constexpr auto flags(cr3_flags flags) -> void + { + m_flags = static_cast(flags); + } + + //! Add the given flags to the current set of encoded root configuration flags of this value. + //! + //! @param flags The root configuration flags to add. + //! @return A reference to this value. + constexpr auto operator|=(cr3_flags flags) -> cr3_value & + { + m_flags |= static_cast(flags); + return *this; + } + + //! Mask the root configuration flags of this value. + //! + //! @param mask The mask to apply to the root configuration flags. + //! @return A reference to this value. + constexpr auto operator&=(cr3_flags mask) -> cr3_value & + { + m_flags &= static_cast(mask); + return *this; + } + + private: + //! Reserved bits. + std::uint64_t : 3; + //! The root paging configuration flags. + std::uint64_t m_flags : 2 {}; + //! Reserved bits. + std::uint64_t : 7; + //! The page aligned physical address of the root page map. + std::uint64_t m_address : 52 {}; + }; + + static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); + +} // namespace teachos::cpu::x86_64 + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/cpu/control_registers.hpp b/arch/x86_64/include/x86_64/cpu/control_registers.hpp deleted file mode 100644 index 1f8c690..0000000 --- a/arch/x86_64/include/x86_64/cpu/control_registers.hpp +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP -#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP - -// IWYU pragma: private, include "x86_64/cpu/registers.hpp" - -#include "kapi/memory/address.hpp" - -#include - -#include -#include -#include - -namespace teachos::cpu::x86_64 -{ - namespace impl - { - //! The assembler templates used to access (r/w) CR0; - constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; - - //! The assembler templates used to access (r/w) CR2; - constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; - - //! The assembler templates used to access (r/w) CR3; - constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; - } // namespace impl - - //! The flags that can be set on CR0 configuration register. - enum struct cr0_flags : uint64_t - { - //! Enable protected mode. - protection_enable = 1uz << 0, - //! Enable wait-monitoring of the coprocessor after task switching. - monitor_coprocessor = 1uz << 1, - //! Emulate floating point coprocessor. - emulation = 1uz << 2, - //! Marks that a task switch has occurred. - task_switched = 1uz << 3, - //! Marks Intel 387 DX math coprocessor as available - extension_type = 1uz << 4, - //! Numeric error handling mode. - numeric_error = 1uz << 5, - //! Disable writing to read-only marked memory. - write_protect = 1uz << 16, - //! Enable Ring-3 alignment checks - alignment_check = 1uz << 18, - //! Disable write through - not_write_through = 1uz << 29, - //! Disable caching of memory accesses - cache_disable = 1uz << 30, - //! Enable paging - paging = 1uz << 31 - }; - - enum struct cr3_flags : std::uint64_t - { - page_level_write_through = 1uz << 0, - page_level_cache_disable = 1uz << 1, - }; -} // namespace teachos::cpu::x86_64 - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; - - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -namespace teachos::cpu::x86_64 -{ - //! A mixin for flag-oriented control registers. - //! - //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A - //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct control_register_with_flags - { - }; - - //! @copydoc control_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the control register - //! is an enum. - template - struct control_register_with_flags>> - { - //! The type of the flags used by this control register - using flags = ValueType; - - //! Set one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be set in the control register. - auto static set(ValueType value) -> void - { - auto current = Derived::read(); - current |= value; - Derived::write(current); - } - - //! Clear one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be cleared in the control register. - auto static clear(ValueType value) -> void - { - auto current = Derived::read(); - current &= ~value; - Derived::write(current); - } - }; - - //! A CPU control register. - //! - //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU - //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU - //! in an invalid/undefined state. - template - struct control_register : control_register_with_flags, ValueType> - { - //! Read the current value of the control register. - //! - //! @return The currently set value of the control register. - [[nodiscard]] auto static read() -> ValueType - { - auto value = ValueType{}; - asm volatile((AssemblerTemplates->first) : "=r"(value)); - return value; - } - - //! Write a new value to the control register. - //! - //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value The new value to write to the control register. - auto static write(ValueType value) -> void - { - asm volatile((AssemblerTemplates->second) : : "r"(value)); - } - }; - - //! The value type of the CR3 control register. - //! - //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the - //! page aligned physical address of the root page map, as well as the root paging configuration flags. - struct cr3_value - { - //! Contstruct a 0-value CR3 value. - constexpr cr3_value() = default; - - //! Construct a CR3 value using the given root page map address and flags. - //! - //! @param address The physical address of the root page map - //! @param flags The root configuration flags of the paging system. - constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast(0)) - : m_flags{static_cast(flags)} - , m_address{static_cast(address.raw())} - {} - - //! Extract the physical address of the root page map from this value. - //! - //! @return The physical address of the root page map. - [[nodiscard]] constexpr auto address() const -> memory::physical_address - { - return memory::physical_address{m_address}; - } - - //! Encode the page aligned physical address of the root page map into this value. - //! - //! @param address The page aligned physical address of the root page map. - constexpr auto address(memory::physical_address address) -> void - { - m_address = static_cast(address.raw()); - } - - //! Extract the root paging configuration flags from this value. - //! - //! @return The root paging configuration flags. - [[nodiscard]] constexpr auto flags() const -> cr3_flags - { - return static_cast(m_flags); - } - - //! Encode the root paging configuration flags into this value. - //! - //! @param flags The root paging configuration flags. - constexpr auto flags(cr3_flags flags) -> void - { - m_flags = static_cast(flags); - } - - //! Add the given flags to the current set of encoded root configuration flags of this value. - //! - //! @param flags The root configuration flags to add. - //! @return A reference to this value. - constexpr auto operator|=(cr3_flags flags) -> cr3_value & - { - m_flags |= static_cast(flags); - return *this; - } - - //! Mask the root configuration flags of this value. - //! - //! @param mask The mask to apply to the root configuration flags. - //! @return A reference to this value. - constexpr auto operator&=(cr3_flags mask) -> cr3_value & - { - m_flags &= static_cast(mask); - return *this; - } - - private: - //! Reserved bits. - std::uint64_t : 3; - //! The root paging configuration flags. - std::uint64_t m_flags : 2 {}; - //! Reserved bits. - std::uint64_t : 7; - //! The page aligned physical address of the root page map. - std::uint64_t m_address : 52 {}; - }; - - static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); - - //! Configuration Register 0. - //! - //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. - using cr0 = control_register; - - //! Configuration Register 2. - //! - //! This configuration register holds the memory address the access to which has triggered the most recent page fault. - using cr2 = control_register; - - //! Configuration Register 3. - //! - //! This register holds the configuration of the virtual memory protection configuration. - using cr3 = control_register; - -} // namespace teachos::cpu::x86_64 - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp b/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp index 080b280..857b444 100644 --- a/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp +++ b/arch/x86_64/include/x86_64/cpu/model_specific_register.hpp @@ -143,9 +143,6 @@ namespace teachos::cpu::x86_64 } }; - //! The I32_EFER (Extended Feature Enable Register) MSR - using i32_efer = 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 cb56270..8eb89e3 100644 --- a/arch/x86_64/include/x86_64/cpu/registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -1,7 +1,30 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include "x86_64/cpu/control_registers.hpp" // IWYU pragma: export +#include "x86_64/cpu/control_register.hpp" // IWYU pragma: export #include "x86_64/cpu/model_specific_register.hpp" // IWYU pragma: export +namespace teachos::cpu::x86_64 +{ + + //! Configuration Register 0. + //! + //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. + using cr0 = control_register; + + //! Configuration Register 2. + //! + //! This configuration register holds the memory address the access to which has triggered the most recent page fault. + using cr2 = control_register; + + //! Configuration Register 3. + //! + //! This register holds the configuration of the virtual memory protection configuration. + using cr3 = control_register; + + //! The I32_EFER (Extended Feature Enable Register) MSR + using i32_efer = model_specific_register; + +} // namespace teachos::cpu::x86_64 + #endif \ No newline at end of file -- cgit v1.2.3 From 50c9c9a1d963e66f7658ab31e9ecd65bf227cfff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 14:07:28 +0100 Subject: x86_64/memory: clean up dependencies --- .../x86_64/include/x86_64/memory/kernel_mapper.hpp | 6 ++- arch/x86_64/include/x86_64/memory/page_table.hpp | 54 ++++++++++++++++++++++ arch/x86_64/include/x86_64/memory/paging_root.hpp | 22 +-------- .../include/x86_64/memory/scoped_mapping.hpp | 4 +- 4 files changed, 62 insertions(+), 24 deletions(-) (limited to 'arch/x86_64/include') 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 1f217ae..5b9c2fd 100644 --- a/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp +++ b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP #define TEACHOS_X86_64_KERNEL_MAPPER_HPP +#include "kapi/memory.hpp" + #include #include #include @@ -16,10 +18,10 @@ namespace teachos::memory::x86_64 explicit kernel_mapper(multiboot2::information_view const * mbi); - auto remap_kernel() -> void; + auto remap_kernel(page_mapper & mapper) -> void; private: - auto map_section(section_header_type const & section, std::string_view name) -> void; + auto map_section(section_header_type const & section, std::string_view name, page_mapper & mapper) -> void; multiboot2::information_view const * m_mbi; std::uintptr_t m_kernel_load_base; 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 3bc2a2b..71ba5b7 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -3,6 +3,8 @@ #include "kapi/memory.hpp" +#include "x86_64/memory/page_utilities.hpp" + #include #include @@ -183,6 +185,58 @@ namespace teachos::memory::x86_64 }); } + [[nodiscard]] auto translate(linear_address address) const -> std::optional + requires(Level == 4) + { + auto offset = address.raw() % page::size; + return translate(page::containing(address)).transform([offset](auto frame) -> auto { + return physical_address{frame.start_address().raw() + offset}; + }); + } + + [[nodiscard]] auto translate(page page) const -> std::optional + requires(Level == 4) + { + 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) + { + return std::nullopt; + } + else if (pml3_entry->huge()) + { + auto pml3_entry_frame = *pml3_entry->frame(); + return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; + } + + auto pml2 = (*pml3)->next(pml_index<3>(page)); + auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; }); + if (!pml2_entry) + { + return std::nullopt; + } + else if (pml2_entry->huge()) + { + auto pml2_entry_frame = *pml2_entry->frame(); + return frame{pml2_entry_frame.number() + pml_index<1>(page)}; + } + + return std::nullopt; + }; + + return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); }) + .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); }) + .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); }) + .or_else(handle_huge_page); + } + private: //! The number of address bits used to represent the page index per level. constexpr auto static level_bits = 9; 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 75ba120..47ee2f9 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -1,19 +1,15 @@ #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 &; + auto static get() -> paging_root *; paging_root(paging_root const &) = delete; paging_root(paging_root &&) = delete; @@ -22,22 +18,6 @@ namespace teachos::memory::x86_64 ~paging_root() = delete; - [[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. - 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 page) -> void; - private: paging_root() = default; }; 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 415ea8e..835e2df 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -22,7 +22,8 @@ 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. - explicit scoped_mapping(page page); + //! @param mapper The page mapper to use for mapping and unmapping of the page. + explicit scoped_mapping(page page, page_mapper & mapper); //! Unmap the mapped frame if one was mapped. //! @note Any page tables that were allocated to support the mapping will be released. @@ -56,6 +57,7 @@ namespace teachos::memory::x86_64 private: page m_page; + page_mapper * m_mapper; bool m_mapped; }; -- cgit v1.2.3 From 40804526a58ddf2cc0df0750550c8dcfa7b7c57c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 11:34:30 +0100 Subject: x86_64/boot: use high-mem address of MBI --- arch/x86_64/include/x86_64/boot/boot.hpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 6dcd2de..2c44659 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -56,7 +56,10 @@ namespace teachos::boot struct information { + //! A pointer to the loader provided Multiboot2 Information structure. multiboot2::information_view const * mbi; + + //! The index of the next character to be written in the VGA text buffer after handoff. std::size_t vga_buffer_index; }; -- cgit v1.2.3 From a9eeec745e29d89afd48ee43d09432eb6fc35be7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 17:04:15 +0100 Subject: kapi/memory: initialize memory subsystem --- arch/x86_64/include/x86_64/memory/buffered_allocator.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp index d7e9491..90ac878 100644 --- a/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp +++ b/arch/x86_64/include/x86_64/memory/buffered_allocator.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace teachos::memory::x86_64 { @@ -20,7 +21,7 @@ namespace teachos::memory::x86_64 } buffered_allocator(buffered_allocator const &) = delete; - buffered_allocator(buffered_allocator &&) = default; + buffered_allocator(buffered_allocator && other) noexcept = delete; ~buffered_allocator() override { -- cgit v1.2.3