From b7a37a1899772e16ce5550c6be3ff9cfd9825fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 27 Feb 2025 08:20:21 +0000 Subject: Add inital empty files for GDT --- .../include/arch/context_switching/descriptor_table/access_bytes.hpp | 0 arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp | 0 .../arch/context_switching/descriptor_table/global_descriptor_table.hpp | 0 .../arch/context_switching/descriptor_table/segment_descriptor.hpp | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/access_bytes.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_bytes.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_bytes.hpp new file mode 100644 index 0000000..e69de29 diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp new file mode 100644 index 0000000..e69de29 diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp new file mode 100644 index 0000000..e69de29 diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3 From 8d14c729c43ee555c240a043e3909617e4fa5043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 27 Feb 2025 09:24:17 +0000 Subject: Add files to cmake and implement gdt flags --- arch/x86_64/CMakeLists.txt | 9 +++ .../descriptor_table/gdt_flags.hpp | 68 ++++++++++++++++++++++ .../descriptor_table/gdt_flags.cpp | 6 ++ 3 files changed, 83 insertions(+) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index e9f8d5f..8cb1ca2 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -81,6 +81,15 @@ target_sources("_exception" PRIVATE "src/exception_handling/pure_virtual.cpp" ) +#[============================================================================[ +# The Context switching Library +#]============================================================================] + +target_sources("_context" PRIVATE + "src/context_switching/descriptor_table/gdt_flags.cpp" + "src/context_switching/descriptor_table/access_byte.cpp" +) + #[============================================================================[ # The Bootable ISO Image #]============================================================================] diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index e69de29..83a7c06 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -0,0 +1,68 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP + +#include +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief Defines helper function for all states that the global descriptor flags of a segment descriptor can + * have. + * + * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + */ + struct gdt_flags + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint8_t + { + GRANULARITY = 1U << 0U, ///< Indicates the size the Limit value in the segement descriptor is scaled by 1 Byte + ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. + PROTECTED_MODE_SEGMENT_16_OR_32_BIT_SIZE = 1U << 1U, ///< Descriptor defines either a 16-bit protected mdoe + ///< segment if bit is not set or 32-bit if the bit is set. + ENABLE_LONG_MODE = 1U << 2U ///< If set the descriptor defines a 64-bit code segment, when set + ///< PROTECTED_MODE_SEGMENT_16_OR_32_BIT_SIZE should always be clear. For other types + ///< of segments bit should not be set. + }; + + /** + * @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. Only the first 3 bit of the value will actually be converted + * into the std::bitset, because the latter 4 bits are not relevant and the 4th bit is reserved. + */ + explicit gdt_flags(uint8_t flags) + : flags(flags >> 5U) + { + // 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<4U> 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==(gdt_flags const & other) const -> bool = default; + + private: + std::bitset<4U> flags; ///< Underlying bitset used to read the flags from. + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp new file mode 100644 index 0000000..8a05956 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp @@ -0,0 +1,6 @@ +#include "arch/context_switching/descriptor_table/gdt_flags.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (flags & other) == other; } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From d8a8efe3e8d90ec83069d1c934ff319626e87a2d Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Feb 2025 10:13:35 +0000 Subject: add descriptor_table access_byte --- .../descriptor_table/access_byte.hpp | 87 ++++++++++++++++++++++ .../descriptor_table/access_bytes.hpp | 0 arch/x86_64/src/boot/boot.s | 4 +- .../descriptor_table/access_byte.cpp | 14 ++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/access_bytes.hpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp new file mode 100644 index 0000000..b3bce11 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -0,0 +1,87 @@ + +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_POINTERS_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_POINTERS_HPP + +#include +#include +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + enum class privilege_level + { + KERNEL = 0, + ADMIN = 1, + PRIVILEGED_USER = 2, + USER = 3 + }; + + /// @brief Defines the access byte of a Descriptor Table + struct access_byte + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint8_t + { + PRESENT = 1U << 0U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. + PRIVILEGE_LEVEL = 1U << 1U | 1 << 2U, ///< Descriptor privilege level field. + ///< Contains the CPU Privilege level of the segment. + DESCRIPTOR_TYPE = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). + EXECUTABLE = 1U << 4U, ///< Defines a data segment (if 0) or a code segment which can be executed from (if 1). + CONFORMING = 1U << 5U, ///< For data selectors: Direction bit + ///< Grows up (if 0), grows down (if 1) + ///< For code selectors: Conforming bit + ///< Code can only be executed from the DPL ring (if 0) + ///< Code can be executed from equal or lower DPL ring (if 1) + READ_WRITE = 1U << 6U, ///< For code segments: Readable bit + ///< For data segments: Writeable bit (read is always allowed) + ACCESSED = 1U << 7U ///< Set, when the segment is accessed. If GDT descriptor is stored in read only pages and + ///< this bit is set to 0, the CPU trying to set this bit will trigger a page fault. + }; + + /** + * @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 access_byte(uint8_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<8U> other) const -> bool; + + /** + * @brief Returns the privilege level of the current access_byte + * + * @return privilege_level + */ + auto get_privilege_level() const -> privilege_level; + + /** + * @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==(access_byte const & other) const -> bool = default; + + private: + std::bitset<8U> flags; ///< Underlying bitset used to read the flags from + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_POINTERS_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_bytes.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_bytes.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 2197dce..dbea42a 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -197,10 +197,10 @@ _start: call enable_paging call enable_sse - cli // Clears the interrupt flag during the GDT setup + cli /* Clears the interrupt flag during the GDT setup */ lgdt (global_descriptor_table_pointer) jmp $global_descriptor_table_code,$_transition_to_long_mode - // The interrupt flag is set in cpp after setting up the GDT + /* The interrupt flag is set in cpp after setting up the GDT */ call halt diff --git a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp new file mode 100644 index 0000000..15a0947 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp @@ -0,0 +1,14 @@ +#include "arch/context_switching/descriptor_table/access_byte.hpp" + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + auto access_byte::contains_flags(std::bitset<8U> other) const -> bool { return (flags & other) == other; } + + auto access_byte::get_privilege_level() const -> privilege_level + { + constexpr uint8_t PRIVILEGE_MASK = 0b0110'0000; + return static_cast(flags.to_ulong() & PRIVILEGE_MASK); + } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From 2f7db60472629dbd191c00e6010d120a046f5ab9 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Feb 2025 13:09:55 +0000 Subject: start segment_descriptor --- .../descriptor_table/access_byte.hpp | 6 ++-- .../descriptor_table/segment_descriptor.hpp | 41 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index b3bce11..36b22ce 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -1,6 +1,6 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_POINTERS_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_POINTERS_HPP +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP #include #include @@ -84,4 +84,4 @@ namespace teachos::arch::context_switching::descriptor_table }; } // namespace teachos::arch::context_switching::descriptor_table -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_POINTERS_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index e69de29..ced0d89 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -0,0 +1,41 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP + +#include "arch/context_switching/descriptor_table/gdt_flags.hpp" + +#include +#include +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + struct segment_descriptor + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint64_t + { + BASE = 1U << 0U, + FLAGS = 1U << 8U, + LIMIT = 1U << 12U, + ACCESS_BYTE = 1U << 16U, + BASE = 1U << 32U, + BASE = 1U << 40U, + LIMIT = 1U << 56U + }; + + explicit segment_descriptor(uint64_t flags) + : flags(flags) + { + // Nothing to do + } + + private: + std::uint8_t base1; + gdt_flags flags; + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP \ No newline at end of file -- cgit v1.2.3 From 56ee767e37cdccae333b292f2fd4c7b2123a7108 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Feb 2025 13:12:06 +0000 Subject: add comment --- .../arch/context_switching/descriptor_table/segment_descriptor.hpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index ced0d89..8428dfa 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -9,6 +9,11 @@ namespace teachos::arch::context_switching::descriptor_table { + + /* + TODO: Lookup segment_descriptor in intel manual chapter 3.4.5 + */ + struct segment_descriptor { /** -- cgit v1.2.3 From 051307f49f4cdfb86c527a475ab21feea4a664d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 4 Mar 2025 18:01:49 +0000 Subject: Add more methods to vector to mimic stl interface partially. --- arch/x86_64/include/arch/stl/shared_pointer.hpp | 2 + arch/x86_64/include/arch/stl/vector.hpp | 381 ++++++++++++++++++------ arch/x86_64/src/memory/main.cpp | 9 + 3 files changed, 306 insertions(+), 86 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/stl/shared_pointer.hpp b/arch/x86_64/include/arch/stl/shared_pointer.hpp index 79a9f82..4a9dec5 100644 --- a/arch/x86_64/include/arch/stl/shared_pointer.hpp +++ b/arch/x86_64/include/arch/stl/shared_pointer.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP #define TEACHOS_ARCH_X86_64_STL_SHARED_POINTER_HPP +#include + namespace teachos::arch::stl { template diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index 62be704..5bebf62 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -2,190 +2,399 @@ #define TEACHOS_ARCH_X86_64_STL_VECTOR_HPP #include "arch/exception_handling/panic.hpp" -#include "arch/shared/container.hpp" -#include "arch/shared/contiguous_pointer_iterator.hpp" #include +#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 + * custom memory management. * - * @tparam T Element the vector instance should contain + * @tparam T Element the vector instance should contain. */ template struct vector { /** - * @brief Defaulted constructor. Initalizes empty vector + * @brief Defaulted constructor. Initalizes empty vector. */ vector() = default; /** * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value + * constructed value. * - * @param capacity 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 + * @param capacity 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. */ - vector(size_t capacity, T initial = T{}) - : capacity(capacity) - , size(capacity) - , data(new T[capacity]{}) + explicit vector(size_t capacity, T initial = T{}) + : _size(capacity) + , _capacity(capacity) + , _data(new T[_capacity]{}) { - auto const begin = data; - auto const end = data + size; - vector_container container{begin, end}; - std::ranges::fill(container, inital); + std::ranges::fill(begin(), end(), initial); } /** - * @brief Copy constructor + * @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 T[_capacity]{}) + { + std::copy(first, last, _data); + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + explicit vector(std::initializer_list initalizer_list) + : _size(initalizer_list.size()) + , _capacity(initalizer_list.size()) + , _data(new T[_capacity]{}) + { + std::copy(initalizer_list.begin(), initalizer_list.end(), _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 + * elements from it. * - * @param other Other instance of vector we want to copy the data from + * @param other Other instance of vector we want to copy the data from. */ vector(vector const & other) - : size(size) - , capacity(capacity) + : _size(other._size) + , _capacity(other._capacity) { - delete[] data; - data = new T[capacity]{}; - - auto const begin = other.data; - auto const end = other.data + size; - vector_container container{begin, end}; - std::ranges::copy(container, data); + delete[] _data; + _data = new T[_capacity]{}; + std::copy(other.begin(), other.end(), _data); } /** - * @brief Copy assignment operator + * @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 + * elements from it. * - * @param other Other instance of vector we want to copy the data from - * @return Newly created copy + * @param other Other instance of vector we want to copy the data from. + * @return Newly created copy. */ vector & operator=(vector const & other) { - delete[] data; - size = other.size(); - capacity = other.capacity(); - data = new T[capacity]{}; - - auto const begin = other.data; - auto const end = other.data + size; - vector_container container{begin, end}; - std::ranges::copy(container, data); + delete[] _data; + _size = other._size; + _capacity = other._capacity; + _data = new T[_capacity]{}; + std::copy(other.begin(), other.end(), _data); return *this; } /** - * @brief Destructor + * @brief Destructor. */ - ~vector() { delete[] data; } + ~vector() { delete[] _data; } /** * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically + * that is the case the capacity is increased automatically. * - * @return Current amount of elements + * @return Current amount of elements. */ - size_t size() const { return size; } + size_t size() const { 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 + * exactly require to decrease the amount of allocations and deallocation to improve speed. * - * @return Current amount of space the vector has for elements + * @return Current amount of space the vector has for elements. */ - size_t capacity() const { return capacity; } + size_t capacity() const { return _capacity; } /** - * @brief Array indexing operator. Allowing to access element at the given index + * @brief Array indexing operator. Allowing to access element at the given index. * - * @note Does not do any bounds checks use at() for that + * @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 + * @param index Index we want to access elements at. + * @return Reference to the underlying element. */ - T & operator[](size_t index) { return data[index]; } + T & operator[](size_t index) { return _data[index]; } /** - * @brief Array indexing operator. Allowing to access element at the given 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 + * @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 + * @param index Index we want to access elements at. + * @return Reference to the underlying element. */ T & at(size_t index) { - if (index >= size) + if (index >= _size) { exception_handling::panic("[Vector] Attempted to read element at invalid index"); } - return this->operator[](size); + return this->operator[](index); } - void push_back(T & const element) {} + /** + * @brief Appends the given element value to the end of the container. The new element is initalized as a copy of + * value. + * + * @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. + * + * @param value The value of the element to append. + */ + void push_back(T const & value) + { + _data[_size] = value; + _size++; - void emplace_back(T && const element) + if (_size == _capacity) + { + reserve(_capacity * 2); + } + } + + /** + * @brief Appends the given element value to the end of the container. Value is moved into the new element. + * + * @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. + * + * @param value The value of the element to append. + */ + void push_back(T && value) { - // If no cacacity, increase capacity - if (size == capacity) + _data[_size] = std::move(value); + _size++; + + if (_size == _capacity) { - reserve(capacity * 2); + reserve(_capacity * 2); } + } - data[size] = element; - 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. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return T& + */ + template + auto emplace_back(Args &&... args) -> T & + { + _data[_size] = T{std::forward(args)...}; + auto const index = _size++; + + if (_size == _capacity) + { + reserve(_capacity * 2); + } + 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. + */ void pop_back() { - if (size <= 0) + if (_size <= 0) { exception_handling::panic("[Vector] Attempted to pop back last element of already empty vector"); } - size--; + _size--; } - T & front() { 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. + */ + T * begin() noexcept { 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. + */ + T const * begin() const noexcept { 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. + */ + T const * cbegin() const noexcept { return begin(); } + + /** + * @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. + */ + T * end() noexcept { 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. + */ + T const * end() const noexcept { 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. + */ + T const * cend() const noexcept { return end(); } + + /** + * @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. + */ + T * data() { 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. + */ + T const * data() const { return _data; } - T & back() { return *(data + size); } + /** + * @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. + */ + T & front() { 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. + */ + T const & front() const { 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. + */ + T & back() { return *end(); } + + /** + * @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. + */ + T const & back() const { return *end(); } + + /** + * @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 + */ void reserve(size_t new_capacity) { - if (new_capacity < size) + if (new_capacity <= _capacity) { - // Creating new array with less capacity than is required to keep all current elements makes no sense return; } - T * temp = new T[new_capacity]; + _capacity = new_capacity; + T * temp = new T[_capacity]{}; + std::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } - auto const begin = other.data; - auto const end = other.data + capacity; - vector_container container{begin, end}; - std::ranges::copy(container, 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. + */ + void shrink_to_fit() + { + if (_size == _capacity) + { + return; + } - delete[] data; - capacity = new_capacity; - data = temp; + _capacity = _size; + T * temp = new T[_capacity]{}; + std::copy(begin(), end(), temp); + delete[] _data; + _data = temp; } private: - T * data = {}; ///< Pointer to the first element in the underlying data container - size_t capacity = {}; ///< Amount of space for elements in the underlying data container - size_t size = {}; ///< Amount of elements in the underlying data container - - typedef shared::container> vector_container; + size_t _size = {}; ///< Amount of elements in the underlying data container + size_t _capacity = {}; ///< Amount of space for elements in the underlying data container + T * _data = {}; ///< Pointer to the first element in the underlying data container }; } // namespace teachos::arch::stl diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a6f91d9..08308db 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -7,6 +7,9 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" +#include "arch/stl/shared_pointer.hpp" +#include "arch/stl/unique_pointer.hpp" +#include "arch/stl/vector.hpp" namespace teachos::arch::memory { @@ -49,5 +52,11 @@ namespace teachos::arch::memory remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); + + auto test2 = stl::make_unique(0); + auto test3 = stl::make_shared(0); + if (test2 && test3) + { + } } } // namespace teachos::arch::memory -- cgit v1.2.3 From 06d5e5872838bd1528493b62b4dc28d44b54aa47 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 9 Mar 2025 09:30:01 +0000 Subject: add doxygen comments to shared and unique pointer --- arch/x86_64/include/arch/stl/shared_pointer.hpp | 93 ++++++++++++++++++++++++- arch/x86_64/include/arch/stl/unique_pointer.hpp | 71 ++++++++++++++++++- arch/x86_64/src/memory/main.cpp | 8 +-- 3 files changed, 162 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/stl/shared_pointer.hpp b/arch/x86_64/include/arch/stl/shared_pointer.hpp index 4a9dec5..80ca7fe 100644 --- a/arch/x86_64/include/arch/stl/shared_pointer.hpp +++ b/arch/x86_64/include/arch/stl/shared_pointer.hpp @@ -5,15 +5,33 @@ namespace teachos::arch::stl { + /** + * @brief A simple implementation of a shared pointer. + * + * This class provides reference counting and automatic resource management + * for dynamically allocated objects. + * + * @tparam T The type of the managed object. + */ template struct shared_pointer { + /** + * @brief Constructs a shared pointer. + * + * @param pointer Raw pointer to manage (default is nullptr). + */ explicit shared_pointer(T * pointer = nullptr) : pointer(pointer) , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) { } + /** + * @brief Copy constructor. + * + * @param other The shared_pointer to copy from. + */ shared_pointer(const shared_pointer & other) : pointer(other.pointer) , ref_count(other.ref_count) @@ -24,6 +42,11 @@ namespace teachos::arch::stl } } + /** + * @brief Move constructor. + * + * @param other The shared_pointer to move from. + */ shared_pointer(shared_pointer && other) noexcept : pointer(other.pointer) , ref_count(other.ref_count) @@ -32,6 +55,12 @@ namespace teachos::arch::stl other.ref_count = nullptr; } + /** + * @brief Copy assignment operator. + * + * @param other The shared_pointer to copy from. + * @return Reference to this shared_pointer. + */ shared_pointer & operator=(const shared_pointer & other) { if (this != &other) @@ -49,6 +78,12 @@ namespace teachos::arch::stl return *this; } + /** + * @brief Move assignment operator. + * + * @param other The shared_pointer to move from. + * @return Reference to this shared_pointer. + */ shared_pointer & operator=(shared_pointer && other) noexcept { if (this != &other) @@ -63,8 +98,14 @@ namespace teachos::arch::stl return *this; } + /** + * @brief Destructor. Cleans up resources if necessary. + */ ~shared_pointer() { cleanup(); } + /** + * @brief Releases ownership and deletes the object if necessary. + */ void cleanup() { if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) @@ -74,6 +115,11 @@ namespace teachos::arch::stl } } + /** + * @brief Resets the shared pointer with a new raw pointer. + * + * @param p New raw pointer (default is nullptr). + */ void reset(T * p = nullptr) { cleanup(); @@ -81,18 +127,43 @@ namespace teachos::arch::stl ref_count = new std::atomic(p != nullptr ? 1 : 0); } + /** + * @brief Swaps the contents of this shared pointer with another. + * + * @param other The shared_pointer to swap with. + */ void swap(shared_pointer & other) { std::swap(pointer, other.pointer); std::swap(ref_count, other.ref_count); } + /** + * @brief Dereference operator. + * + * @return Reference to the managed object. + */ T & operator*() const { return *pointer; } + /** + * @brief Member access operator. + * + * @return Pointer to the managed object. + */ T * operator->() const { return pointer; } + /** + * @brief Returns the raw pointer. + * + * @return Pointer to the managed object. + */ T * get() const { return pointer; } + /** + * @brief Returns the reference count. + * + * @return Number of shared_pointer instances managing the same object. + */ int use_count() const { if (pointer != nullptr) @@ -103,15 +174,33 @@ namespace teachos::arch::stl return 0; } + /** + * @brief Checks if this is the only shared pointer managing the object. + * + * @return True if the use count is 1, otherwise false. + */ bool unique() const { return use_count() == 1; } + /** + * @brief Checks if the shared pointer is not empty. + * + * @return True if the pointer is not null, otherwise false. + */ explicit operator bool() const { return pointer != nullptr; } private: - T * pointer; - std::atomic * ref_count; + T * pointer; ///< The managed object. + std::atomic * ref_count; ///< Reference count. }; + /** + * @brief Creates a shared pointer instance. + * + * @tparam T The type of object to allocate. + * @tparam Args Argument types for the constructor of T. + * @param args Arguments for the constructor of T. + * @return A shared_pointer instance managing a newly created object. + */ template shared_pointer make_shared(Args &&... args) { diff --git a/arch/x86_64/include/arch/stl/unique_pointer.hpp b/arch/x86_64/include/arch/stl/unique_pointer.hpp index 0ec3c38..08c862d 100644 --- a/arch/x86_64/include/arch/stl/unique_pointer.hpp +++ b/arch/x86_64/include/arch/stl/unique_pointer.hpp @@ -3,25 +3,56 @@ namespace teachos::arch::stl { + /** + * @brief A simple unique pointer implementation. + * + * @tparam T Type of the managed object. + */ template struct unique_pointer { + /** + * @brief Constructs a unique pointer. + * + * @param ptr Pointer to manage, default is nullptr. + */ explicit unique_pointer(T * ptr = nullptr) : pointer(ptr) { } + /** + * @brief Destructor that deletes the managed object. + */ ~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. + */ unique_pointer & operator=(const unique_pointer &) = delete; + /** + * @brief Move constructor. + * + * @param other Unique pointer to move from. + */ unique_pointer(unique_pointer && other) noexcept : pointer(other.pointer) { other.pointer = nullptr; } + /** + * @brief Move assignment operator. + * + * @param other Unique pointer to move from. + * @return Reference to this unique pointer. + */ unique_pointer & operator=(unique_pointer && other) noexcept { if (this != &other) @@ -33,12 +64,32 @@ namespace teachos::arch::stl return *this; } + /** + * @brief Dereference operator. + * + * @return Reference to the managed object. + */ T & operator*() const { return *pointer; } + /** + * @brief Member access operator. + * + * @return Pointer to the managed object. + */ T * operator->() const { return pointer; } + /** + * @brief Gets the raw pointer. + * + * @return The managed pointer. + */ T * get() const { return pointer; } + /** + * @brief Releases ownership of the managed object. + * + * @return The raw pointer and sets internal pointer to nullptr. + */ T * release() { T * temp = pointer; @@ -46,18 +97,36 @@ namespace teachos::arch::stl return temp; } + /** + * @brief Resets the managed object. + * + * @param ptr New pointer to manage (default is nullptr). + */ void reset(T * ptr = nullptr) { delete pointer; pointer = ptr; } + /** + * @brief Swaps the managed object with another unique pointer. + * + * @param other Unique pointer to swap with. + */ void swap(unique_pointer & other) { std::swap(pointer, other.pointer); } private: - T * pointer; + T * pointer; ///< The managed pointer. }; + /** + * @brief Creates a unique pointer instance. + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args Arguments for T's constructor. + * @return A unique pointer managing a newly created T object. + */ template unique_pointer make_unique(Args &&... args) { diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 08308db..15e89c0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -52,11 +52,5 @@ namespace teachos::arch::memory remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - - auto test2 = stl::make_unique(0); - auto test3 = stl::make_shared(0); - if (test2 && test3) - { - } } -} // namespace teachos::arch::memory +} // namespace teachos::arch::memory \ No newline at end of file -- cgit v1.2.3 From 1a6d41362447531a2ea5ee344c15b9aaa6c2090a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 9 Mar 2025 16:52:17 +0000 Subject: Adjust comments and implement remaining interface for STL classes. --- arch/x86_64/include/arch/stl/shared_pointer.hpp | 142 ++++++++++++++---------- arch/x86_64/include/arch/stl/unique_pointer.hpp | 96 +++++++++++----- arch/x86_64/include/arch/stl/vector.hpp | 18 +-- arch/x86_64/src/memory/main.cpp | 5 +- 4 files changed, 163 insertions(+), 98 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/stl/shared_pointer.hpp b/arch/x86_64/include/arch/stl/shared_pointer.hpp index 80ca7fe..1ddc182 100644 --- a/arch/x86_64/include/arch/stl/shared_pointer.hpp +++ b/arch/x86_64/include/arch/stl/shared_pointer.hpp @@ -6,10 +6,14 @@ namespace teachos::arch::stl { /** - * @brief A simple implementation of a shared pointer. - * - * This class provides reference counting and automatic resource management - * for dynamically allocated objects. + * @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. */ @@ -17,14 +21,15 @@ namespace teachos::arch::stl struct shared_pointer { /** - * @brief Constructs a shared pointer. + * @brief Constructor. * - * @param pointer Raw pointer to manage (default is nullptr). + * @param pointer A pointer to an object to manage (default is nullptr). */ explicit shared_pointer(T * pointer = nullptr) : pointer(pointer) - , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) + , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) { + // Nothing to do. } /** @@ -56,10 +61,12 @@ namespace teachos::arch::stl } /** - * @brief Copy assignment operator. + * @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 The shared_pointer to copy from. - * @return Reference to this shared_pointer. + * @param other Another smart pointer to share the ownership with. + * @return Reference to this shared pointer. */ shared_pointer & operator=(const shared_pointer & other) { @@ -79,10 +86,11 @@ namespace teachos::arch::stl } /** - * @brief Move assignment operator. + * @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 The shared_pointer to move from. - * @return Reference to this shared_pointer. + * @param other Another smart pointer to acquire the ownership from. + * @return Reference to this shared pointer. */ shared_pointer & operator=(shared_pointer && other) noexcept { @@ -104,31 +112,20 @@ namespace teachos::arch::stl ~shared_pointer() { cleanup(); } /** - * @brief Releases ownership and deletes the object if necessary. - */ - void cleanup() - { - if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) - { - delete pointer; - delete ref_count; - } - } - - /** - * @brief Resets the shared pointer with a new raw pointer. + * @brief Replaces the managed object. * - * @param p New raw pointer (default is nullptr). + * @param ptr Pointer to a new object to manage (default = nullptr). */ - void reset(T * p = nullptr) + void reset(T * ptr = nullptr) { cleanup(); - pointer = p; - ref_count = new std::atomic(p != nullptr ? 1 : 0); + pointer = ptr; + ref_count = new std::atomic(ptr != nullptr ? 1 : 0); } /** - * @brief Swaps the contents of this shared pointer with another. + * @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. */ @@ -139,32 +136,38 @@ namespace teachos::arch::stl } /** - * @brief Dereference operator. + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. * - * @return Reference to the managed object. + * @return Returns the object owned by *this, equivalent to *get(). */ - T & operator*() const { return *pointer; } + auto operator*() const -> T & { return *pointer; } /** * @brief Member access operator. * - * @return Pointer to the managed object. + * @return Returns a pointer to the object owned by *this, i.e. get(). */ - T * operator->() const { return pointer; } + auto operator->() const -> T * { return pointer; } /** - * @brief Returns the raw pointer. + * @brief Returns a pointer to the managed object or nullptr if no object is owned. * - * @return Pointer to the managed object. + * @return Pointer to the managed object or nullptr if no object is owned. */ - T * get() const { return pointer; } + auto get() const -> T * { return pointer; } /** - * @brief Returns the reference count. + * @brief Returns the number of different shared_pointer instances (*this included) managing the current object. If + * there is no managed object, ​0​ is returned. * - * @return Number of shared_pointer instances managing the same object. + * @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. */ - int use_count() const + auto use_count() const -> std::size_t { if (pointer != nullptr) { @@ -175,34 +178,59 @@ namespace teachos::arch::stl } /** - * @brief Checks if this is the only shared pointer managing the object. + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. * - * @return True if the use count is 1, otherwise false. + * @return true if *this owns an object, false otherwise. */ - bool unique() const { return use_count() == 1; } + explicit operator bool() const { return pointer != nullptr; } /** - * @brief Checks if the shared pointer is not empty. - * - * @return True if the pointer is not null, otherwise false. + * @brief Defaulted three-way comparator operator. */ - explicit operator bool() const { return pointer != nullptr; } + auto operator<=>(const shared_pointer & other) const = default; private: - T * pointer; ///< The managed object. - std::atomic * ref_count; ///< Reference count. + /** + * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. + */ + 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 Creates a shared pointer instance. + * @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 The type of object to allocate. - * @tparam Args Argument types for the constructor of T. - * @param args Arguments for the constructor of T. - * @return A shared_pointer instance managing a newly created object. + * @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 - shared_pointer make_shared(Args &&... args) + auto make_shared(Args &&... args) -> shared_pointer { return shared_pointer(new T(std::forward(args)...)); } diff --git a/arch/x86_64/include/arch/stl/unique_pointer.hpp b/arch/x86_64/include/arch/stl/unique_pointer.hpp index 08c862d..899a35b 100644 --- a/arch/x86_64/include/arch/stl/unique_pointer.hpp +++ b/arch/x86_64/include/arch/stl/unique_pointer.hpp @@ -4,7 +4,8 @@ namespace teachos::arch::stl { /** - * @brief A simple unique pointer implementation. + * @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. */ @@ -12,13 +13,14 @@ namespace teachos::arch::stl struct unique_pointer { /** - * @brief Constructs a unique pointer. + * @brief Constructor. * - * @param ptr Pointer to manage, default is nullptr. + * @param ptr A pointer to an object to manage (default is nullptr). */ explicit unique_pointer(T * ptr = nullptr) : pointer(ptr) { + // Nothing to do. } /** @@ -34,7 +36,7 @@ namespace teachos::arch::stl /** * @brief Deleted copy assignment operator to enforce unique ownership. */ - unique_pointer & operator=(const unique_pointer &) = delete; + auto operator=(const unique_pointer &) -> unique_pointer & = delete; /** * @brief Move constructor. @@ -48,12 +50,12 @@ namespace teachos::arch::stl } /** - * @brief Move assignment operator. + * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). * - * @param other Unique pointer to move from. + * @param other Smart pointer from which ownership will be transferred. * @return Reference to this unique pointer. */ - unique_pointer & operator=(unique_pointer && other) noexcept + auto operator=(unique_pointer && other) noexcept -> unique_pointer & { if (this != &other) { @@ -65,32 +67,42 @@ namespace teachos::arch::stl } /** - * @brief Dereference operator. + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. * - * @return Reference to the managed object. + * @return Returns the object owned by *this, equivalent to *get(). */ - T & operator*() const { return *pointer; } + auto operator*() const -> T & { return *pointer; } /** * @brief Member access operator. * - * @return Pointer to the managed object. + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + 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. */ - T * operator->() const { return pointer; } + auto get() const -> T * { return pointer; } /** - * @brief Gets the raw pointer. + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. * - * @return The managed pointer. + * @return true if *this owns an object, false otherwise. */ - T * get() const { return pointer; } + explicit operator bool() const noexcept { return pointer != nullptr; } /** - * @brief Releases ownership of the managed object. + * @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 The raw pointer and sets internal pointer to nullptr. + * @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. */ - T * release() + auto release() -> T * { T * temp = pointer; pointer = nullptr; @@ -98,37 +110,65 @@ namespace teachos::arch::stl } /** - * @brief Resets the managed object. + * @brief Replaces the managed object. * - * @param ptr New pointer to manage (default is nullptr). + * @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). */ - void reset(T * ptr = nullptr) + auto reset(T * ptr = nullptr) -> void { delete pointer; pointer = ptr; } /** - * @brief Swaps the managed object with another unique pointer. + * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. * - * @param other Unique pointer to swap with. + * @param other Another unique_ptr object to swap the managed object and the deleter with. */ - void swap(unique_pointer & other) { std::swap(pointer, other.pointer); } + auto swap(unique_pointer & other) -> void + { + using std::swap; + swap(pointer, other.pointer); + } + + /** + * @brief Defaulted three-way comparator operator. + */ + auto operator<=>(const unique_pointer & other) const = default; private: T * pointer; ///< The managed pointer. }; /** - * @brief Creates a unique pointer instance. + * @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 Arguments for T's constructor. - * @return A unique pointer managing a newly created T object. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Unique_pointer of an instance of type T. */ template - unique_pointer make_unique(Args &&... args) + auto make_unique(Args &&... args) -> unique_pointer { return unique_pointer(new T(std::forward(args)...)); } diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index 5bebf62..b8bedf3 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -29,7 +29,7 @@ namespace teachos::arch::stl * @param capacity 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_t capacity, T initial = T{}) + explicit vector(std::size_t capacity, T initial = T{}) : _size(capacity) , _capacity(capacity) , _data(new T[_capacity]{}) @@ -113,7 +113,7 @@ namespace teachos::arch::stl * * @return Current amount of elements. */ - size_t size() const { return _size; } + std::size_t size() const { return _size; } /** * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we @@ -121,7 +121,7 @@ namespace teachos::arch::stl * * @return Current amount of space the vector has for elements. */ - size_t capacity() const { return _capacity; } + std::size_t capacity() const { return _capacity; } /** * @brief Array indexing operator. Allowing to access element at the given index. @@ -131,7 +131,7 @@ namespace teachos::arch::stl * @param index Index we want to access elements at. * @return Reference to the underlying element. */ - T & operator[](size_t index) { return _data[index]; } + T & operator[](std::size_t index) { return _data[index]; } /** * @brief Array indexing operator. Allowing to access element at the given index. @@ -141,7 +141,7 @@ namespace teachos::arch::stl * @param index Index we want to access elements at. * @return Reference to the underlying element. */ - T & at(size_t index) + T & at(std::size_t index) { if (index >= _size) { @@ -357,7 +357,7 @@ namespace teachos::arch::stl * * @param new_capacity New capacity of the vector, in number of elements */ - void reserve(size_t new_capacity) + void reserve(std::size_t new_capacity) { if (new_capacity <= _capacity) { @@ -392,9 +392,9 @@ namespace teachos::arch::stl } private: - size_t _size = {}; ///< Amount of elements in the underlying data container - size_t _capacity = {}; ///< Amount of space for elements in the underlying data container - T * _data = {}; ///< Pointer to the first element in the underlying data container + std::size_t _size = {}; ///< Amount of elements in the underlying data container + std::size_t _capacity = {}; ///< Amount of space for elements in the underlying data container + T * _data = {}; ///< Pointer to the first element in the underlying data container }; } // namespace teachos::arch::stl diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 15e89c0..a6f91d9 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -7,9 +7,6 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -#include "arch/stl/shared_pointer.hpp" -#include "arch/stl/unique_pointer.hpp" -#include "arch/stl/vector.hpp" namespace teachos::arch::memory { @@ -53,4 +50,4 @@ namespace teachos::arch::memory video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -} // namespace teachos::arch::memory \ No newline at end of file +} // namespace teachos::arch::memory -- cgit v1.2.3 From c5151739698620e77622423c109e638f903f01c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 10 Mar 2025 13:42:38 +0000 Subject: Adjust register segment descriptors to possible states --- arch/x86_64/CMakeLists.txt | 1 + .../descriptor_table/access_byte.hpp | 60 +++++++--------- .../descriptor_table/gdt_flags.hpp | 49 ++++++++------ .../descriptor_table/segment_descriptor.hpp | 2 - .../descriptor_table/segment_descriptor_type.hpp | 27 ++++++++ .../descriptor_table/type_field.hpp | 79 ++++++++++++++++++++++ .../descriptor_table/access_byte.cpp | 15 ++-- .../descriptor_table/gdt_flags.cpp | 24 ++++++- .../descriptor_table/type_field.cpp | 12 ++++ 9 files changed, 201 insertions(+), 68 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/type_field.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8cb1ca2..19c71be 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -88,6 +88,7 @@ target_sources("_exception" PRIVATE target_sources("_context" PRIVATE "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/access_byte.cpp" + "src/context_switching/descriptor_table/type_field.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index 36b22ce..c510170 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -2,21 +2,16 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP +#include "arch/context_switching/descriptor_table/type_field.hpp" + #include -#include -#include namespace teachos::arch::context_switching::descriptor_table { - enum class privilege_level - { - KERNEL = 0, - ADMIN = 1, - PRIVILEGED_USER = 2, - USER = 3 - }; - - /// @brief Defines the access byte of a Descriptor Table + /** + * @brief Defines helper function for all states that the access byte field of a segment descriptor can + * have. + */ struct access_byte { /** @@ -24,21 +19,17 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - PRESENT = 1U << 0U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. - PRIVILEGE_LEVEL = 1U << 1U | 1 << 2U, ///< Descriptor privilege level field. - ///< Contains the CPU Privilege level of the segment. - DESCRIPTOR_TYPE = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). - EXECUTABLE = 1U << 4U, ///< Defines a data segment (if 0) or a code segment which can be executed from (if 1). - CONFORMING = 1U << 5U, ///< For data selectors: Direction bit - ///< Grows up (if 0), grows down (if 1) - ///< For code selectors: Conforming bit - ///< Code can only be executed from the DPL ring (if 0) - ///< Code can be executed from equal or lower DPL ring (if 1) - READ_WRITE = 1U << 6U, ///< For code segments: Readable bit - ///< For data segments: Writeable bit (read is always allowed) - ACCESSED = 1U << 7U ///< Set, when the segment is accessed. If GDT descriptor is stored in read only pages and - ///< this bit is set to 0, the CPU trying to set this bit will trigger a page fault. + PRESENT = 1U << 0U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. + ACCESS_LEVEL_KERNEL = 0, ///< Highest privileged level used by the kernel to allow for full access of resources. + ACCESS_LEVEL_ADMIN = + 2, ///< 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. + ACCESS_LEVEL_PRIVILEGED_USER = + 4, ///< 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. + ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. + DESCRIPTOR_TYPE = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). }; /** @@ -47,11 +38,7 @@ namespace teachos::arch::context_switching::descriptor_table * @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 access_byte(uint8_t flags) - : flags(flags) - { - // Nothing to do - } + access_byte(uint8_t flags); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -62,14 +49,14 @@ namespace teachos::arch::context_switching::descriptor_table * @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<8U> other) const -> bool; + auto contains_flags(std::bitset<4U> other) const -> bool; /** - * @brief Returns the privilege level of the current access_byte + * @brief Returns the type field of the access byte. * - * @return privilege_level + * @return Copy of the underlying type field bits. */ - auto get_privilege_level() const -> privilege_level; + auto get_type_field() const -> type_field; /** * @brief Allows to compare the underlying std::bitset of two instances. @@ -80,7 +67,8 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(access_byte const & other) const -> bool = default; private: - std::bitset<8U> flags; ///< Underlying bitset used to read the flags from + std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. + type_field _type; ///< Field specifying the type of the segment descriptor and its settings. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index 83a7c06..ef8f2fa 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -1,16 +1,15 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP + +#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" #include -#include namespace teachos::arch::context_switching::descriptor_table { /** - * @brief Defines helper function for all states that the global descriptor flags of a segment descriptor can + * @brief Defines helper function for all states that the flags field of a segment descriptor can * have. - * - * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ struct gdt_flags { @@ -19,27 +18,33 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - GRANULARITY = 1U << 0U, ///< Indicates the size the Limit value in the segement descriptor is scaled by 1 Byte - ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. - PROTECTED_MODE_SEGMENT_16_OR_32_BIT_SIZE = 1U << 1U, ///< Descriptor defines either a 16-bit protected mdoe - ///< segment if bit is not set or 32-bit if the bit is set. - ENABLE_LONG_MODE = 1U << 2U ///< If set the descriptor defines a 64-bit code segment, when set - ///< PROTECTED_MODE_SEGMENT_16_OR_32_BIT_SIZE should always be clear. For other types - ///< of segments bit should not be set. + GRANULARITY = 1U << 0U, ///< Indicates the size the Limit value in the segement descriptor is scaled by 1 Byte + ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. + DEFAULT_LENGTH = 1U << 1U, ///< Indicates the default length for code segments with effective addresses and + ///< operands. Enable for 32 bit, 16 bit otherwise. + STACK_POINTER_SIZE = 1U << 1U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for + ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. + UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 + ///< GiB, 4 KiB otherwise. + LENGTH = 1U << 2U ///< 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, otherwis they are executed in compatability 32-bit mode. If bis is set the + ///< DEFAULT_LENGTH bis needs to be 0 }; /** * @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. Only the first 3 bit of the value will actually be converted - * into the std::bitset, because the latter 4 bits are not relevant and the 4th bit is reserved. + * allow reading the state of single bits more easily. Only the rightmost 3 bit of the value will actually be + * converted into the std::bitset, because the leftmost 4 bit are irrelevant and the 4th bit is reserved. + * + * @param type Depending on the segment descriptor type some of the passed bits are ignored. For system segment only + * the first bit Granularity is relevant, for the data segment the 3rd bit Length is irrelevant and for the code + * segment all bits are relevant. Bits that are not relevant will simply not be read and saved into the underlying + * flags std::bitset. */ - explicit gdt_flags(uint8_t flags) - : flags(flags >> 5U) - { - // Nothing to do - } + gdt_flags(uint8_t flags, segment_descriptor_type type); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -61,8 +66,8 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(gdt_flags const & other) const -> bool = default; private: - std::bitset<4U> flags; ///< Underlying bitset used to read the flags from. + std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. }; } // namespace teachos::arch::context_switching::descriptor_table -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 8428dfa..b7665d9 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -4,8 +4,6 @@ #include "arch/context_switching/descriptor_table/gdt_flags.hpp" #include -#include -#include namespace teachos::arch::context_switching::descriptor_table { diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp new file mode 100644 index 0000000..4815fca --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP + +#include + +namespace teachos::arch::context_switching::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::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp new file mode 100644 index 0000000..88e25cf --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp @@ -0,0 +1,79 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP + +#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief Defines helper function for all states that the flags field of a segment descriptor can + * have. + */ + struct type_field + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint8_t + { + TYPE = 1U << 0U, ///< Further defines the actual type of the segment. If enabled this segment is a code segment, + ///< otherwise its a data segment. + EXPAND_UP = 1U << 1U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the + ///< data segment expands downwards, otherwise it expands upwards. + CONFORMING = + 1U << 1U, ///< 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. + WRITABLE = 1U << 2U, ///< 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 << 2U, ///< 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. + ACCESSED = + 1U + << 3U, ///< 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. + 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. + }; + + /** + * @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. + */ + type_field(uint8_t flags); + + /** + * @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<4U> 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==(type_field const & other) const -> bool = default; + + private: + std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP diff --git a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp index 15a0947..7a2b0b0 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp @@ -1,14 +1,15 @@ #include "arch/context_switching/descriptor_table/access_byte.hpp" -#include - namespace teachos::arch::context_switching::descriptor_table { - auto access_byte::contains_flags(std::bitset<8U> other) const -> bool { return (flags & other) == other; } - - auto access_byte::get_privilege_level() const -> privilege_level + access_byte::access_byte(uint8_t flags) + : _flags(flags) + , _type(flags) { - constexpr uint8_t PRIVILEGE_MASK = 0b0110'0000; - return static_cast(flags.to_ulong() & PRIVILEGE_MASK); + // Nothing to do. } + + auto access_byte::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } + + auto access_byte::get_type_field() const -> type_field { return _type; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp index 8a05956..8e1e939 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp @@ -1,6 +1,28 @@ #include "arch/context_switching/descriptor_table/gdt_flags.hpp" +#include "arch/exception_handling/assert.hpp" + namespace teachos::arch::context_switching::descriptor_table { - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (flags & other) == other; } + gdt_flags::gdt_flags(uint8_t flags, segment_descriptor_type type) + : _flags(flags << 5U) + { + switch (type) + { + case segment_descriptor_type::SYSTEM_SEGMENT: + _flags.set(2, false); + _flags.set(3, false); + break; + case segment_descriptor_type::DATA_SEGMENT: + _flags.set(3, false); + break; + case segment_descriptor_type::CODE_SEGMENT: + exception_handling::assert((contains_flags(LENGTH) && !contains_flags(DEFAULT_LENGTH)) || + !contains_flags(LENGTH), + "[GDT] Flags of code segment descriptor has both "); + break; + } + } + + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp b/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp new file mode 100644 index 0000000..d967a97 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp @@ -0,0 +1,12 @@ +#include "arch/context_switching/descriptor_table/type_field.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + type_field::type_field(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto type_field::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From 52fffdf2c76def4a875e0328eb45d74c6e97e805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 10 Mar 2025 16:05:31 +0000 Subject: Adjust segment descriptor to use defined helpers --- arch/x86_64/CMakeLists.txt | 1 + .../descriptor_table/segment_descriptor.hpp | 54 +++++++++++----------- .../descriptor_table/segment_descriptor.cpp | 13 ++++++ 3 files changed, 41 insertions(+), 27 deletions(-) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 19c71be..1b8349a 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -89,6 +89,7 @@ target_sources("_context" PRIVATE "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/access_byte.cpp" "src/context_switching/descriptor_table/type_field.cpp" + "src/context_switching/descriptor_table/segment_descriptor.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index b7665d9..59f99f6 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -1,44 +1,44 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP +#include "arch/context_switching/descriptor_table/access_byte.hpp" #include "arch/context_switching/descriptor_table/gdt_flags.hpp" - -#include +#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" +#include "arch/context_switching/descriptor_table/type_field.hpp" namespace teachos::arch::context_switching::descriptor_table { + __extension__ typedef __int128 int128_t; + __extension__ typedef unsigned __int128 uint128_t; - /* - TODO: Lookup segment_descriptor in intel manual chapter 3.4.5 - */ - + /** + * @brief Defines helper function for all states and the actual data the segment descriptor can have. + */ struct segment_descriptor { /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + * @brief Constructor. + * + * @note Created segment descriptor copies the given bytes into theese components ending with a 32 bit reserved + * field that has to be used, because the 64-bit segment descriptor needs to be big enough for two 32-bit segment + * descriptor. + * - 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. */ - enum bitset : uint64_t - { - BASE = 1U << 0U, - FLAGS = 1U << 8U, - LIMIT = 1U << 12U, - ACCESS_BYTE = 1U << 16U, - BASE = 1U << 32U, - BASE = 1U << 40U, - LIMIT = 1U << 56U - }; - - explicit segment_descriptor(uint64_t flags) - : flags(flags) - { - // Nothing to do - } + explicit segment_descriptor(uint128_t flags); private: - std::uint8_t base1; - gdt_flags flags; - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from + uint32_t _reserved; + access_byte _access; + gdt_flags _flag; + uint64_t _base; + std::bitset<20U> _limit; }; } // namespace teachos::arch::context_switching::descriptor_table -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp new file mode 100644 index 0000000..fb9c034 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + segment_descriptor::segment_descriptor(uint128_t flags) + : _reserved(flags) + , _access(flags) + , _flag(flags, segment_descriptor_type::SYSTEM_SEGMENT) + , _base(flags) + , _limit(flags) + { + } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From 569cf73d1fa14ec11afbb37464d2c356d55d64b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 10 Mar 2025 16:35:01 +0000 Subject: Implement segment descriptor --- .../descriptor_table/access_byte.hpp | 4 ++-- .../descriptor_table/gdt_flags.hpp | 7 +------ .../descriptor_table/segment_descriptor.hpp | 5 +++++ .../descriptor_table/type_field.hpp | 8 ++++---- .../descriptor_table/gdt_flags.cpp | 18 ++---------------- .../descriptor_table/segment_descriptor.cpp | 21 ++++++++++++++++----- 6 files changed, 30 insertions(+), 33 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index c510170..d1b579d 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -28,8 +28,8 @@ namespace teachos::arch::context_switching::descriptor_table ACCESS_LEVEL_PRIVILEGED_USER = 4, ///< 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. - ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. - DESCRIPTOR_TYPE = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). + ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. + CODE_OR_DATA_SEGMENT = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). }; /** diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index ef8f2fa..bc6ecb7 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -38,13 +38,8 @@ namespace teachos::arch::context_switching::descriptor_table * @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. Only the rightmost 3 bit of the value will actually be * converted into the std::bitset, because the leftmost 4 bit are irrelevant and the 4th bit is reserved. - * - * @param type Depending on the segment descriptor type some of the passed bits are ignored. For system segment only - * the first bit Granularity is relevant, for the data segment the 3rd bit Length is irrelevant and for the code - * segment all bits are relevant. Bits that are not relevant will simply not be read and saved into the underlying - * flags std::bitset. */ - gdt_flags(uint8_t flags, segment_descriptor_type type); + gdt_flags(uint8_t flags); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 59f99f6..364e546 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -32,6 +32,11 @@ namespace teachos::arch::context_switching::descriptor_table */ explicit segment_descriptor(uint128_t flags); + /** + * @brief Calculates the underlying segment type that this segement descriptor is describing. + */ + auto get_segment_type() const -> segment_descriptor_type; + private: uint32_t _reserved; access_byte _access; diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp index 88e25cf..da61d38 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp @@ -18,10 +18,10 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - TYPE = 1U << 0U, ///< Further defines the actual type of the segment. If enabled this segment is a code segment, - ///< otherwise its a data segment. - EXPAND_UP = 1U << 1U, ///< 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 << 0U, ///< Further defines the actual type of the segment. If enabled this segment is a code + ///< segment, otherwise its a data segment. + EXPAND_UP = 1U << 1U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the + ///< data segment expands downwards, otherwise it expands upwards. CONFORMING = 1U << 1U, ///< 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 diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp index 8e1e939..8fbf869 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp @@ -4,24 +4,10 @@ namespace teachos::arch::context_switching::descriptor_table { - gdt_flags::gdt_flags(uint8_t flags, segment_descriptor_type type) + gdt_flags::gdt_flags(uint8_t flags) : _flags(flags << 5U) { - switch (type) - { - case segment_descriptor_type::SYSTEM_SEGMENT: - _flags.set(2, false); - _flags.set(3, false); - break; - case segment_descriptor_type::DATA_SEGMENT: - _flags.set(3, false); - break; - case segment_descriptor_type::CODE_SEGMENT: - exception_handling::assert((contains_flags(LENGTH) && !contains_flags(DEFAULT_LENGTH)) || - !contains_flags(LENGTH), - "[GDT] Flags of code segment descriptor has both "); - break; - } + // Nothing to do. } auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp index fb9c034..57564f2 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -3,11 +3,22 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) - : _reserved(flags) - , _access(flags) - , _flag(flags, segment_descriptor_type::SYSTEM_SEGMENT) - , _base(flags) - , _limit(flags) + : _reserved(flags >> 96U) + , _access((flags >> 40U) << 80U) + , _flag((flags >> 52U) << 72U) + , _base(((flags >> 64U) << 32U) << 32U | ((flags >> 56U) << 64U) << 24U | (flags >> 16U) << 88U) + , _limit(((flags >> 48U) << 72U) << 16U | flags << 112U) { + // Nothing to do. + } + + auto segment_descriptor::get_segment_type() const -> segment_descriptor_type + { + if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) + { + return segment_descriptor_type::SYSTEM_SEGMENT; + } + return _access.get_type_field().contains_flags(type_field::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; } } // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From b8a0024ee71a64ec0e87a1e2d0c0c7280dc954e6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 09:36:00 +0000 Subject: create GDT and fix segment descriptor bit order --- .../descriptor_table/access_byte.hpp | 23 ++++++---- .../descriptor_table/gdt_flags.hpp | 27 +++++++----- .../descriptor_table/segment_descriptor.hpp | 23 +++++++--- .../descriptor_table/type_field.hpp | 33 ++++++++------ arch/x86_64/include/arch/stl/vector.hpp | 2 +- .../descriptor_table/access_byte.cpp | 4 +- .../descriptor_table/gdt_flags.cpp | 2 +- .../descriptor_table/segment_descriptor.cpp | 22 ++++++++-- arch/x86_64/src/kernel/main.cpp | 50 ++++++++++++++++++++++ 9 files changed, 140 insertions(+), 46 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index d1b579d..dc4de03 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -19,8 +19,7 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - PRESENT = 1U << 0U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. + CODE_OR_DATA_SEGMENT = 1U << 0U, ///< Defines a system segment (if 0) or a code/data segment (if 1). ACCESS_LEVEL_KERNEL = 0, ///< Highest privileged level used by the kernel to allow for full access of resources. ACCESS_LEVEL_ADMIN = 2, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more @@ -28,17 +27,23 @@ namespace teachos::arch::context_switching::descriptor_table ACCESS_LEVEL_PRIVILEGED_USER = 4, ///< 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. - ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. - CODE_OR_DATA_SEGMENT = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). + ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. + PRESENT = 1U << 3U, ///< 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 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. + * @param flags Left-most four bits of the access_byte. + * @param type_field Right-most four bits of the access_byte representing the type_field. */ - access_byte(uint8_t flags); + access_byte(uint8_t flags, uint8_t type_field); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -67,8 +72,8 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(access_byte const & other) const -> bool = default; private: - std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. - type_field _type; ///< Field specifying the type of the segment descriptor and its settings. + std::bitset<4U> _flags = {}; ///< Underlying bitset used to read the flags from. + type_field _type = {}; ///< Field specifying the type of the segment descriptor and its settings. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index bc6ecb7..f27284e 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -18,20 +18,25 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - GRANULARITY = 1U << 0U, ///< Indicates the size the Limit value in the segement descriptor is scaled by 1 Byte - ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. - DEFAULT_LENGTH = 1U << 1U, ///< Indicates the default length for code segments with effective addresses and - ///< operands. Enable for 32 bit, 16 bit otherwise. - STACK_POINTER_SIZE = 1U << 1U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for - ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. + LENGTH = 1U << 0U, ///< 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 bis + ///< is set the DEFAULT_LENGTH bis needs to be 0 UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 ///< GiB, 4 KiB otherwise. - LENGTH = 1U << 2U ///< 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, otherwis they are executed in compatability 32-bit mode. If bis is set the - ///< DEFAULT_LENGTH bis needs to be 0 + STACK_POINTER_SIZE = 1U << 1U, ///< 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 << 1U, ///< Indicates the default length for code segments with effective addresses and + ///< operands. Enable for 32 bit, 16 bit otherwise. + GRANULARITY = 1U << 2U, ///< 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. * @@ -61,7 +66,7 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(gdt_flags const & other) const -> bool = default; private: - std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. + std::bitset<4U> _flags = {}; ///< Underlying bitset used to read the flags from. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 364e546..b5697e3 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -16,6 +16,11 @@ namespace teachos::arch::context_switching::descriptor_table */ struct segment_descriptor { + /** + * @brief Default Constructor. + */ + segment_descriptor() = default; + /** * @brief Constructor. * @@ -32,17 +37,25 @@ namespace teachos::arch::context_switching::descriptor_table */ explicit segment_descriptor(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(access_byte access_byte, gdt_flags flags, uint64_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; private: - uint32_t _reserved; - access_byte _access; - gdt_flags _flag; - uint64_t _base; - std::bitset<20U> _limit; + uint32_t _reserved = {}; + access_byte _access = {}; + gdt_flags _flag = {}; + uint64_t _base = {}; + std::bitset<20U> _limit = {}; }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp index da61d38..3822f9c 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp @@ -18,22 +18,22 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - CODE_SEGMENT = 1U << 0U, ///< Further defines the actual type of the segment. If enabled this segment is a code - ///< segment, otherwise its a data segment. - EXPAND_UP = 1U << 1U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the - ///< data segment expands downwards, otherwise it expands upwards. - CONFORMING = - 1U << 1U, ///< 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. - WRITABLE = 1U << 2U, ///< 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 << 2U, ///< 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. ACCESSED = 1U - << 3U, ///< Whether the segment has been accessed since the last time the operating system has cleared the + << 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. @@ -44,6 +44,11 @@ namespace teachos::arch::context_switching::descriptor_table TRAP_GATE = 15 ///< The actual type of sytem segment is a trap gate. }; + /** + * @brief Default Constructor. + */ + type_field() = default; + /** * @brief Constructor. * @@ -72,7 +77,7 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(type_field const & other) const -> bool = default; private: - std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. + std::bitset<4U> _flags = {}; ///< Underlying bitset used to read the flags from. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index b8bedf3..112af57 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -18,7 +18,7 @@ namespace teachos::arch::stl struct vector { /** - * @brief Defaulted constructor. Initalizes empty vector. + * @brief Default Constructor. */ vector() = default; diff --git a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp index 7a2b0b0..4e5459f 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp @@ -2,9 +2,9 @@ namespace teachos::arch::context_switching::descriptor_table { - access_byte::access_byte(uint8_t flags) + access_byte::access_byte(uint8_t flags, uint8_t type_field) : _flags(flags) - , _type(flags) + , _type(type_field) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp index 8fbf869..65f2e90 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp @@ -5,7 +5,7 @@ namespace teachos::arch::context_switching::descriptor_table { gdt_flags::gdt_flags(uint8_t flags) - : _flags(flags << 5U) + : _flags(flags) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp index 57564f2..ab8eaba 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) : _reserved(flags >> 96U) - , _access((flags >> 40U) << 80U) + , _access((flags >> 44U) << 80U, (flags >> 40U) << 84U) , _flag((flags >> 52U) << 72U) , _base(((flags >> 64U) << 32U) << 32U | ((flags >> 56U) << 64U) << 24U | (flags >> 16U) << 88U) , _limit(((flags >> 48U) << 72U) << 16U | flags << 112U) @@ -12,13 +12,29 @@ namespace teachos::arch::context_switching::descriptor_table // Nothing to do. } + segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, + std::bitset<20U> limit) + : _reserved(0U) + , _access(access_byte) + , _flag(flags) + , _base(base) + , _limit(limit) + { + // Nothing to do + } + auto segment_descriptor::get_segment_type() const -> segment_descriptor_type { if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) { return segment_descriptor_type::SYSTEM_SEGMENT; } - return _access.get_type_field().contains_flags(type_field::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; + + if (_access.get_type_field().contains_flags(type_field::CODE_SEGMENT)) + { + return segment_descriptor_type::CODE_SEGMENT; + } + + return segment_descriptor_type::DATA_SEGMENT; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 472aed5..d3938ed 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,9 +1,11 @@ #include "arch/kernel/main.hpp" +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" #include "arch/memory/multiboot/reader.hpp" +#include "arch/stl/vector.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::kernel @@ -57,5 +59,53 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); heap_test(); + + using context_switching::descriptor_table::access_byte; + using context_switching::descriptor_table::gdt_flags; + using context_switching::descriptor_table::segment_descriptor; + using context_switching::descriptor_table::segment_descriptor_type; + using context_switching::descriptor_table::type_field; + + segment_descriptor null_segment{0}; + + // Kernel space code segment + access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::CODE_SEGMENT | type_field::READABLE}; + gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; + segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, 0xFFFFF}; + + // Kernel space data segment + access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::WRITABLE}; + gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; + segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, 0xFFFFF}; + + // User space code segment + access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::CODE_SEGMENT | type_field::READABLE}; + gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; + segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, 0xFFFFF}; + + // User space data segment + access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::WRITABLE}; + gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; + segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, 0xFFFFF}; + + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; + + decltype(auto) x = global_descriptor_table.at(1); + if (global_descriptor_table.size() == 0) + { + } + if (x.get_segment_type() == segment_descriptor_type::CODE_SEGMENT) + { + } + video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 34c36096e55ac678e29c58f7336b419647e805b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 13 Mar 2025 10:00:42 +0000 Subject: Fix segment descriptor bit order of private members --- .../descriptor_table/segment_descriptor.hpp | 13 ++++++++----- .../descriptor_table/segment_descriptor.cpp | 16 ++++++++++------ 2 files changed, 18 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index b5697e3..06e2e8a 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -51,11 +51,14 @@ namespace teachos::arch::context_switching::descriptor_table auto get_segment_type() const -> segment_descriptor_type; private: - uint32_t _reserved = {}; - access_byte _access = {}; - gdt_flags _flag = {}; - uint64_t _base = {}; - std::bitset<20U> _limit = {}; + // The order in private variables starts for the first variable being the rightmost bit. + std::bitset<16U> _limit_1 = {}; ///< First part of the limit field (0 - 15) + std::bitset<24U> _base_1 = {}; ///< First part of the base field (16 - 39) + access_byte _access = {}; ///< Access byte field (40 - 47) + std::bitset<4U> _limit_2 = {}; ///< Second part of the limit field (48 - 51) + gdt_flags _flag = {}; ///< Flags field (52 - 55) + std::bitset<40U> _base_2 = {}; ///< Second part of the base field (56 - 95) + uint32_t _reserved = {}; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp index ab8eaba..a743ad2 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -3,22 +3,26 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) - : _reserved(flags >> 96U) + : _limit_1(flags << 112U) + , _base_1((flags >> 16U) << 88U) , _access((flags >> 44U) << 80U, (flags >> 40U) << 84U) + , _limit_2((flags >> 48U) << 72U) , _flag((flags >> 52U) << 72U) - , _base(((flags >> 64U) << 32U) << 32U | ((flags >> 56U) << 64U) << 24U | (flags >> 16U) << 88U) - , _limit(((flags >> 48U) << 72U) << 16U | flags << 112U) + , _base_2((flags >> 56U) << 32U) + , _reserved(flags >> 96U) { // Nothing to do. } segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit) - : _reserved(0U) + : _limit_1((limit.to_ulong() << 4U) >> 16U) + , _base_1((base << 40U) >> 40U) , _access(access_byte) + , _limit_2(limit.to_ulong() >> 16U) , _flag(flags) - , _base(base) - , _limit(limit) + , _base_2(base >> 24U) + , _reserved(0U) { // Nothing to do } -- cgit v1.2.3 From 2e4cbd473ff3bb7ac7371af39becf830b4fb753b Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 14:05:45 +0000 Subject: IN_PROGRESS implement gdt initialization --- arch/x86_64/CMakeLists.txt | 12 ++-- .../descriptor_table/global_descriptor_table.hpp | 19 ++++++ .../global_descriptor_table_pointer.hpp | 23 +++++++ .../include/arch/kernel/cpu/control_register.hpp | 71 +++++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/msr.hpp | 64 +++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/ss.hpp | 56 +++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/tlb.hpp | 27 ++++++++ .../include/arch/memory/cpu/control_register.hpp | 71 --------------------- arch/x86_64/include/arch/memory/cpu/msr.hpp | 64 ------------------- arch/x86_64/include/arch/memory/cpu/tlb.hpp | 27 -------- .../arch/memory/paging/active_page_table.hpp | 6 +- .../include/arch/memory/paging/kernel_mapper.hpp | 2 +- arch/x86_64/src/boot/boot.s | 2 +- .../descriptor_table/global_descriptor_table.cpp | 57 +++++++++++++++++ arch/x86_64/src/kernel/cpu/control_register.cpp | 72 ++++++++++++++++++++++ arch/x86_64/src/kernel/cpu/msr.cpp | 31 ++++++++++ arch/x86_64/src/kernel/cpu/ss.cpp | 33 ++++++++++ arch/x86_64/src/kernel/cpu/tlb.cpp | 16 +++++ arch/x86_64/src/kernel/main.cpp | 44 ++----------- arch/x86_64/src/memory/cpu/control_register.cpp | 72 ---------------------- arch/x86_64/src/memory/cpu/msr.cpp | 31 ---------- arch/x86_64/src/memory/cpu/tlb.cpp | 16 ----- arch/x86_64/src/memory/main.cpp | 4 +- 23 files changed, 487 insertions(+), 333 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/control_register.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/msr.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/ss.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/tlb.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/msr.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/tlb.hpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp create mode 100644 arch/x86_64/src/kernel/cpu/control_register.cpp create mode 100644 arch/x86_64/src/kernel/cpu/msr.cpp create mode 100644 arch/x86_64/src/kernel/cpu/ss.cpp create mode 100644 arch/x86_64/src/kernel/cpu/tlb.cpp delete mode 100644 arch/x86_64/src/memory/cpu/control_register.cpp delete mode 100644 arch/x86_64/src/memory/cpu/msr.cpp delete mode 100644 arch/x86_64/src/memory/cpu/tlb.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1b8349a..9d59d87 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -7,6 +7,10 @@ mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT) target_sources("_kernel" PRIVATE "src/kernel/main.cpp" + "src/kernel/cpu/tlb.cpp" + "src/kernel/cpu/control_register.cpp" + "src/kernel/cpu/msr.cpp" + "src/kernel/cpu/ss.cpp" ) target_link_options("_kernel" PRIVATE @@ -53,9 +57,6 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" - "src/memory/cpu/tlb.cpp" - "src/memory/cpu/control_register.cpp" - "src/memory/cpu/msr.cpp" "src/memory/heap/bump_allocator.cpp" "src/memory/heap/memory_block.cpp" "src/memory/heap/linked_list_allocator.cpp" @@ -86,10 +87,11 @@ target_sources("_exception" PRIVATE #]============================================================================] target_sources("_context" PRIVATE - "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/access_byte.cpp" - "src/context_switching/descriptor_table/type_field.cpp" + "src/context_switching/descriptor_table/gdt_flags.cpp" + "src/context_switching/descriptor_table/global_descriptor_table.cpp" "src/context_switching/descriptor_table/segment_descriptor.cpp" + "src/context_switching/descriptor_table/type_field.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp index e69de29..daba1fe 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/stl/vector.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + typedef stl::vector global_descriptor_table; + + auto create_global_descriptor_table() -> global_descriptor_table; + + auto load_global_descriptor_table(global_descriptor_table_pointer gdt_pointer) -> void; + + auto initialize_global_descriptor_table() -> global_descriptor_table; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp new file mode 100644 index 0000000..c2925fd --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @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 global_descriptor_table_pointer + { + uint16_t table_length; ///< The size of the GDT in bytes. + global_descriptor_table * address; ///< Pointer to the GDT base address. + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_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 new file mode 100644 index 0000000..27c7777 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/control_register.hpp @@ -0,0 +1,71 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP + +#include + +namespace teachos::arch::memory::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::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/include/arch/kernel/cpu/msr.hpp new file mode 100644 index 0000000..52d74bd --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/msr.hpp @@ -0,0 +1,64 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP + +#include +#include + +namespace teachos::arch::memory::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::memory::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/ss.hpp b/arch/x86_64/include/arch/kernel/cpu/ss.hpp new file mode 100644 index 0000000..2d3518e --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/ss.hpp @@ -0,0 +1,56 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP + +#include +#include + +namespace teachos::arch::memory::cpu +{ + /** + * @brief Represents a segment selector in the x86_64 architecture. + * + * 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 segment_selector + { + /** + * @brief Constructs a segment selector. + * + * @param index The index of the segment descriptor. + * @param table_indicator The table indicator (0 for GDT, 1 for LDT). + * @param requested_privilege_level The requested privilege level (0-3). + */ + segment_selector(uint16_t index, std::bitset<1U> table_indicator, std::bitset<2U> requested_privilege_level); + + /** + * @brief Converts the segment selector to a 16-bit value. + * + * @return uint16_t The 16-bit representation of the segment selector. + */ + auto to_uint16() const -> uint16_t; + + private: + uint16_t index; + std::bitset<1U> table_indicator; + std::bitset<2U> requested_privilege_level; + }; + + /** + * @brief Reads the current value of the stack segment (SS) register. + * + * @return uint16_t The current SS register value. + */ + auto read_ss() -> uint16_t; + + /** + * @brief Writes a new value to the stack segment (SS) register. + * + * @param selector The segment selector to be written to SS. + */ + auto write_ss(segment_selector selector) -> void; + +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp new file mode 100644 index 0000000..333cd58 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp @@ -0,0 +1,27 @@ +#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::memory::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(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::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/control_register.hpp b/arch/x86_64/include/arch/memory/cpu/control_register.hpp deleted file mode 100644 index e11813d..0000000 --- a/arch/x86_64/include/arch/memory/cpu/control_register.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP - -#include - -namespace teachos::arch::memory::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::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp deleted file mode 100644 index cda70e2..0000000 --- a/arch/x86_64/include/arch/memory/cpu/msr.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP - -#include -#include - -namespace teachos::arch::memory::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::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/cpu/tlb.hpp b/arch/x86_64/include/arch/memory/cpu/tlb.hpp deleted file mode 100644 index 075d7bb..0000000 --- a/arch/x86_64/include/arch/memory/cpu/tlb.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP - -#include "arch/memory/paging/virtual_page.hpp" - -namespace teachos::arch::memory::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(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::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_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 index 1b2aaed..9846a21 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -2,8 +2,8 @@ #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/cpu/tlb.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -75,8 +75,8 @@ namespace teachos::arch::memory::paging * @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 map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, std::bitset<64U> flags) + -> void { auto current_handle = active_handle; 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 74f1c14..b137736 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP -#include "arch/memory/cpu/control_register.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" diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index dbea42a..39bfe33 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -199,7 +199,7 @@ _start: cli /* Clears the interrupt flag during the GDT setup */ lgdt (global_descriptor_table_pointer) - jmp $global_descriptor_table_code,$_transition_to_long_mode + jmp $global_descriptor_table_code, $_transition_to_long_mode /* The interrupt flag is set in cpp after setting up the GDT */ call halt diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp new file mode 100644 index 0000000..1cba13c --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -0,0 +1,57 @@ +#include "global_descriptor_table.hpp" + +#include "arch/stl/vector.hpp" + +#include "segment_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor null_segment{0}; + + // Kernel space code segment + access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::CODE_SEGMENT | type_field::READABLE}; + gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; + segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, 0xFFFFF}; + + // Kernel space data segment + access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::WRITABLE}; + gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; + segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, 0xFFFFF}; + + // User space code segment + access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::CODE_SEGMENT | type_field::READABLE}; + gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; + segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, 0xFFFFF}; + + // User space data segment + access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::WRITABLE}; + gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; + segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, 0xFFFFF}; + + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; + return global_descriptor_table; + } + + auto load_global_descriptor_table(global_descriptor_table_pointer gdt_pointer) -> void + { + // + } + + auto initialize_global_descriptor_table() -> global_descriptor_table + { + global_descriptor_table gdt{create_global_descriptor_table()}; + global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; + load_global_descriptor_table(gdt_pointer); + } +} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp new file mode 100644 index 0000000..3051bae --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/control_register.cpp @@ -0,0 +1,72 @@ +#include "arch/kernel/cpu/control_register.hpp" + +#include "arch/exception_handling/panic.hpp" + +#include + +namespace teachos::arch::memory::cpu +{ + auto read_control_register(control_register cr) -> uint64_t + { + uint64_t current_value; + switch (cr) + { + case control_register::CR0: + asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR2: + asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR3: + asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR4: + asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); + break; + default: + exception_handling::panic("[Control Register] Attempted to read non-existent or reserved control register"); + break; + } + return current_value; + } + + auto write_control_register(control_register cr, uint64_t new_value) -> void + { + switch (cr) + { + case control_register::CR0: + asm volatile("mov %[input], %%cr0" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR2: + asm volatile("mov %[input], %%cr2" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR3: + asm volatile("mov %[input], %%cr3" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR4: + asm volatile("mov %[input], %%cr4" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + default: + exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); + break; + } + } + + auto set_cr0_bit(cr0_flags flag) -> void + { + auto const cr0 = read_control_register(control_register::CR0); + write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp new file mode 100644 index 0000000..082bca9 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/msr.cpp @@ -0,0 +1,31 @@ +#include "arch/kernel/cpu/msr.hpp" + +namespace teachos::arch::memory::cpu +{ + namespace + { + auto constexpr IA32_EFER_ADDRESS = 0xC0000080; + } + + auto read_msr(uint32_t msr) -> uint64_t + { + uint32_t low, high; + asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); + return (static_cast(high) << 32) | low; + } + + auto write_msr(uint32_t msr, uint64_t value) -> void + { + uint32_t low = value & 0xFFFFFFFF; + uint32_t high = value >> 32; + asm volatile("wrmsr" + : /* no output from call */ + : "c"(msr), "a"(low), "d"(high)); + } + + auto set_efer_bit(efer_flags flag) -> void + { + auto const efer = read_msr(IA32_EFER_ADDRESS); + write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp new file mode 100644 index 0000000..b7e52e1 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -0,0 +1,33 @@ +#include "arch/kernel/cpu/ss.hpp" + +namespace teachos::arch::memory::cpu +{ + segment_selector::segment_selector(uint16_t index, std::bitset<1U> table_indicator, + std::bitset<2U> requested_privilege_level) + : index(index) + , table_indicator(table_indicator) + , requested_privilege_level(requested_privilege_level) + { + // Nothing to do + } + + auto segment_selector::to_uint16() const -> uint16_t + { + return static_cast((index << 3) | (table_indicator.to_ulong() << 2) | + requested_privilege_level.to_ulong()); + } + + auto read_ss() -> uint16_t + { + uint16_t ss; + __asm__("mov %%ss, %0" : "=r"(ss)); + return ss; + } + + auto write_ss(segment_selector selector) -> void + { + uint16_t ss = selector.to_uint16(); + __asm__("mov %0, %%ss" ::"r"(ss)); + } + +} // namespace teachos::arch::memory::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/tlb.cpp b/arch/x86_64/src/kernel/cpu/tlb.cpp new file mode 100644 index 0000000..e753c2c --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/tlb.cpp @@ -0,0 +1,16 @@ +#include "arch/kernel/cpu/tlb.hpp" + +#include "arch/kernel/cpu/control_register.hpp" + +namespace teachos::arch::memory::cpu +{ + auto tlb_flush(paging::virtual_address address) -> void + { + asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); + } + + auto tlb_flush_all() -> void + { + write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index d3938ed..4db9599 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,6 @@ #include "arch/kernel/main.hpp" -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,50 +60,14 @@ namespace teachos::arch::kernel heap_test(); - using context_switching::descriptor_table::access_byte; - using context_switching::descriptor_table::gdt_flags; - using context_switching::descriptor_table::segment_descriptor; - using context_switching::descriptor_table::segment_descriptor_type; - using context_switching::descriptor_table::type_field; - - segment_descriptor null_segment{0}; - - // Kernel space code segment - access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::CODE_SEGMENT | type_field::READABLE}; - gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; - segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, 0xFFFFF}; - - // Kernel space data segment - access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::WRITABLE}; - gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; - segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, 0xFFFFF}; - - // User space code segment - access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::CODE_SEGMENT | type_field::READABLE}; - gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; - segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, 0xFFFFF}; - - // User space data segment - access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::WRITABLE}; - gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; - segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, 0xFFFFF}; - - stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; + context_switching::descriptor_table::global_descriptor_table global_descriptor_table{ + context_switching::descriptor_table::initialize_global_descriptor_table()}; decltype(auto) x = global_descriptor_table.at(1); if (global_descriptor_table.size() == 0) { } - if (x.get_segment_type() == segment_descriptor_type::CODE_SEGMENT) + if (x.get_segment_type() == context_switching::descriptor_table::segment_descriptor_type::CODE_SEGMENT) { } video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/cpu/control_register.cpp b/arch/x86_64/src/memory/cpu/control_register.cpp deleted file mode 100644 index 7ee88b5..0000000 --- a/arch/x86_64/src/memory/cpu/control_register.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "arch/memory/cpu/control_register.hpp" - -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::memory::cpu -{ - auto read_control_register(control_register cr) -> uint64_t - { - uint64_t current_value; - switch (cr) - { - case control_register::CR0: - asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR2: - asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR3: - asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR4: - asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); - break; - default: - exception_handling::panic("[Control Register] Attempted to read non-existent or reserved control register"); - break; - } - return current_value; - } - - auto write_control_register(control_register cr, uint64_t new_value) -> void - { - switch (cr) - { - case control_register::CR0: - asm volatile("mov %[input], %%cr0" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR2: - asm volatile("mov %[input], %%cr2" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR3: - asm volatile("mov %[input], %%cr3" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR4: - asm volatile("mov %[input], %%cr4" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - default: - exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); - break; - } - } - - auto set_cr0_bit(cr0_flags flag) -> void - { - auto const cr0 = read_control_register(control_register::CR0); - write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/msr.cpp b/arch/x86_64/src/memory/cpu/msr.cpp deleted file mode 100644 index b83f902..0000000 --- a/arch/x86_64/src/memory/cpu/msr.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "arch/memory/cpu/msr.hpp" - -namespace teachos::arch::memory::cpu -{ - namespace - { - auto constexpr IA32_EFER_ADDRESS = 0xC0000080; - } - - auto read_msr(uint32_t msr) -> uint64_t - { - uint32_t low, high; - asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); - return (static_cast(high) << 32) | low; - } - - auto write_msr(uint32_t msr, uint64_t value) -> void - { - uint32_t low = value & 0xFFFFFFFF; - uint32_t high = value >> 32; - asm volatile("wrmsr" - : /* no output from call */ - : "c"(msr), "a"(low), "d"(high)); - } - - auto set_efer_bit(efer_flags flag) -> void - { - auto const efer = read_msr(IA32_EFER_ADDRESS); - write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/tlb.cpp b/arch/x86_64/src/memory/cpu/tlb.cpp deleted file mode 100644 index 591d9fc..0000000 --- a/arch/x86_64/src/memory/cpu/tlb.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/memory/cpu/tlb.hpp" - -#include "arch/memory/cpu/control_register.hpp" - -namespace teachos::arch::memory::cpu -{ - auto tlb_flush(paging::virtual_address address) -> void - { - asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); - } - - auto tlb_flush_all() -> void - { - write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a6f91d9..abc7431 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -1,9 +1,9 @@ #include "arch/memory/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/control_register.hpp" +#include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/cpu/control_register.hpp" -#include "arch/memory/cpu/msr.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -- cgit v1.2.3 From 11db9338dac611ea32e202add5ce5055b54ebb58 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 15:46:16 +0000 Subject: fixup typing and continue adding gdt --- arch/x86_64/CMakeLists.txt | 3 ++- .../descriptor_table/global_descriptor_table.hpp | 2 -- .../global_descriptor_table_pointer.hpp | 8 ++++---- .../include/arch/kernel/cpu/control_register.hpp | 4 ++-- arch/x86_64/include/arch/kernel/cpu/lgdt.hpp | 19 +++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/msr.hpp | 4 ++-- arch/x86_64/include/arch/kernel/cpu/ss.hpp | 4 ++-- arch/x86_64/include/arch/kernel/cpu/tlb.hpp | 6 +++--- .../include/arch/memory/paging/active_page_table.hpp | 2 +- .../include/arch/memory/paging/kernel_mapper.hpp | 14 +++++++------- .../descriptor_table/global_descriptor_table.cpp | 17 ++++++++--------- arch/x86_64/src/kernel/cpu/control_register.cpp | 4 ++-- arch/x86_64/src/kernel/cpu/lgdt.cpp | 14 ++++++++++++++ arch/x86_64/src/kernel/cpu/msr.cpp | 4 ++-- arch/x86_64/src/kernel/cpu/ss.cpp | 8 ++++---- arch/x86_64/src/kernel/cpu/tlb.cpp | 6 +++--- arch/x86_64/src/memory/main.cpp | 4 ++-- 17 files changed, 77 insertions(+), 46 deletions(-) create mode 100644 arch/x86_64/include/arch/kernel/cpu/lgdt.hpp create mode 100644 arch/x86_64/src/kernel/cpu/lgdt.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9d59d87..53339d2 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -7,10 +7,11 @@ mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT) target_sources("_kernel" PRIVATE "src/kernel/main.cpp" - "src/kernel/cpu/tlb.cpp" "src/kernel/cpu/control_register.cpp" + "src/kernel/cpu/lgdt.cpp" "src/kernel/cpu/msr.cpp" "src/kernel/cpu/ss.cpp" + "src/kernel/cpu/tlb.cpp" ) target_link_options("_kernel" PRIVATE diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp index daba1fe..45f2d31 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp @@ -11,8 +11,6 @@ namespace teachos::arch::context_switching::descriptor_table auto create_global_descriptor_table() -> global_descriptor_table; - auto load_global_descriptor_table(global_descriptor_table_pointer gdt_pointer) -> void; - auto initialize_global_descriptor_table() -> global_descriptor_table; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp index c2925fd..0305bff 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" - #include namespace teachos::arch::context_switching::descriptor_table @@ -15,8 +13,10 @@ namespace teachos::arch::context_switching::descriptor_table */ struct global_descriptor_table_pointer { - uint16_t table_length; ///< The size of the GDT in bytes. - global_descriptor_table * address; ///< Pointer to the GDT base address. + std::size_t table_length; ///< The size of the GDT in bytes. + + // TODO: Would rather use global_descriptor_table *, but circular dependency + uint64_t address; ///< Pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/kernel/cpu/control_register.hpp b/arch/x86_64/include/arch/kernel/cpu/control_register.hpp index 27c7777..dcaf02d 100644 --- a/arch/x86_64/include/arch/kernel/cpu/control_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/control_register.hpp @@ -3,7 +3,7 @@ #include -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { /** * @brief Control registers that can be read and written to. @@ -66,6 +66,6 @@ namespace teachos::arch::memory::cpu */ auto set_cr0_bit(cr0_flags flag) -> void; -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu #endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp b/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp new file mode 100644 index 0000000..633d460 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +#include +#include + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Loads the global_descriptor_table_pointer into the global descriptor table register (GDTR). + */ + auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer gdt_pointer) + -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/include/arch/kernel/cpu/msr.hpp index 52d74bd..99d6378 100644 --- a/arch/x86_64/include/arch/kernel/cpu/msr.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/msr.hpp @@ -4,7 +4,7 @@ #include #include -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { /** * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). @@ -59,6 +59,6 @@ namespace teachos::arch::memory::cpu */ auto set_efer_bit(efer_flags flag) -> void; -} // namespace teachos::arch::memory::cpu +} // 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/ss.hpp b/arch/x86_64/include/arch/kernel/cpu/ss.hpp index 2d3518e..1fb6448 100644 --- a/arch/x86_64/include/arch/kernel/cpu/ss.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/ss.hpp @@ -4,7 +4,7 @@ #include #include -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { /** * @brief Represents a segment selector in the x86_64 architecture. @@ -51,6 +51,6 @@ namespace teachos::arch::memory::cpu */ auto write_ss(segment_selector selector) -> void; -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu #endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp index 333cd58..f3e58a6 100644 --- a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp @@ -3,7 +3,7 @@ #include "arch/memory/paging/virtual_page.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { /** * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained @@ -12,7 +12,7 @@ namespace teachos::arch::memory::cpu * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for * that page. */ - auto tlb_flush(paging::virtual_address address) -> void; + auto tlb_flush(memory::paging::virtual_address address) -> void; /** * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. @@ -22,6 +22,6 @@ namespace teachos::arch::memory::cpu */ auto tlb_flush_all() -> void; -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu #endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_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 index 9846a21..9e91a8c 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -153,7 +153,7 @@ namespace teachos::arch::memory::paging } unmap_page_table_entry(allocator, page, current_handle); - cpu::tlb_flush(page.start_address()); + kernel::cpu::tlb_flush(page.start_address()); } private: 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 b137736..8d36fde 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -77,16 +77,16 @@ namespace teachos::arch::memory::paging 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(cpu::read_control_register(cpu::control_register::CR3)); + 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); - cpu::tlb_flush_all(); + kernel::cpu::tlb_flush_all(); map_elf_kernel_sections(active_table); page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); + kernel::cpu::tlb_flush_all(); temporary_page.unmap_page(active_table); } @@ -99,12 +99,12 @@ namespace teachos::arch::memory::paging */ auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + 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(); - cpu::write_control_register(cpu::control_register::CR3, new_address); + kernel::cpu::write_control_register(kernel::cpu::control_register::CR3, new_address); return old_table; } diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index 1cba13c..ca3d7ff 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -1,9 +1,9 @@ -#include "global_descriptor_table.hpp" +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/kernel/cpu/lgdt.hpp" #include "arch/stl/vector.hpp" -#include "segment_descriptor.hpp" - namespace teachos::arch::context_switching::descriptor_table { auto create_global_descriptor_table() -> global_descriptor_table @@ -43,15 +43,14 @@ namespace teachos::arch::context_switching::descriptor_table return global_descriptor_table; } - auto load_global_descriptor_table(global_descriptor_table_pointer gdt_pointer) -> void - { - // - } - auto initialize_global_descriptor_table() -> global_descriptor_table { global_descriptor_table gdt{create_global_descriptor_table()}; + + // TODO: Second argument does not work yet (because pointer hpp) global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; - load_global_descriptor_table(gdt_pointer); + kernel::cpu::load_global_descriptor_table(gdt_pointer); + + return gdt; } } // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp index 3051bae..a39a360 100644 --- a/arch/x86_64/src/kernel/cpu/control_register.cpp +++ b/arch/x86_64/src/kernel/cpu/control_register.cpp @@ -4,7 +4,7 @@ #include -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { auto read_control_register(control_register cr) -> uint64_t { @@ -69,4 +69,4 @@ namespace teachos::arch::memory::cpu auto const cr0 = read_control_register(control_register::CR0); write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); } -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp new file mode 100644 index 0000000..cb13aa8 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/lgdt.cpp @@ -0,0 +1,14 @@ +#include "arch/kernel/cpu/lgdt.hpp" + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer gdt_pointer) + -> void + { + // TODO: build lgdt argument from global_descriptor_table_pointer (don't know how yet) + asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); + } + +} // namespace teachos::arch::kernel::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp index 082bca9..6249f8f 100644 --- a/arch/x86_64/src/kernel/cpu/msr.cpp +++ b/arch/x86_64/src/kernel/cpu/msr.cpp @@ -1,6 +1,6 @@ #include "arch/kernel/cpu/msr.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { namespace { @@ -28,4 +28,4 @@ namespace teachos::arch::memory::cpu auto const efer = read_msr(IA32_EFER_ADDRESS); write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); } -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp index b7e52e1..9c8dd61 100644 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -1,6 +1,6 @@ #include "arch/kernel/cpu/ss.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { segment_selector::segment_selector(uint16_t index, std::bitset<1U> table_indicator, std::bitset<2U> requested_privilege_level) @@ -20,14 +20,14 @@ namespace teachos::arch::memory::cpu auto read_ss() -> uint16_t { uint16_t ss; - __asm__("mov %%ss, %0" : "=r"(ss)); + asm volatile("mov %%ss, %0" : "=r"(ss)); return ss; } auto write_ss(segment_selector selector) -> void { uint16_t ss = selector.to_uint16(); - __asm__("mov %0, %%ss" ::"r"(ss)); + asm volatile("mov %0, %%ss" ::"r"(ss)); } -} // namespace teachos::arch::memory::cpu \ No newline at end of file +} // namespace teachos::arch::kernel::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/tlb.cpp b/arch/x86_64/src/kernel/cpu/tlb.cpp index e753c2c..a09001c 100644 --- a/arch/x86_64/src/kernel/cpu/tlb.cpp +++ b/arch/x86_64/src/kernel/cpu/tlb.cpp @@ -2,9 +2,9 @@ #include "arch/kernel/cpu/control_register.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { - auto tlb_flush(paging::virtual_address address) -> void + auto tlb_flush(memory::paging::virtual_address address) -> void { asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); } @@ -13,4 +13,4 @@ namespace teachos::arch::memory::cpu { write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); } -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index abc7431..a920a20 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -38,8 +38,8 @@ namespace teachos::arch::memory auto const memory_information = multiboot::read_multiboot2(); allocator::area_frame_allocator allocator(memory_information); - cpu::set_cr0_bit(memory::cpu::cr0_flags::WRITE_PROTECT); - cpu::set_efer_bit(memory::cpu::efer_flags::NXE); + kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); auto & active_table = kernel.remap_kernel(); -- cgit v1.2.3 From f2b9ac8f0f22354241e9b78e47aa7cb94e5ef511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 14 Mar 2025 14:20:24 +0000 Subject: Fix header recursion problem --- .../descriptor_table/global_descriptor_table.hpp | 4 ---- .../descriptor_table/global_descriptor_table_pointer.hpp | 11 +++++++---- .../descriptor_table/segment_descriptor.hpp | 14 +++++++------- .../descriptor_table/global_descriptor_table.cpp | 7 ++----- arch/x86_64/src/kernel/cpu/lgdt.cpp | 11 +++++++---- 5 files changed, 23 insertions(+), 24 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp index 45f2d31..c4d0e30 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp @@ -2,13 +2,9 @@ #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP #include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" -#include "arch/stl/vector.hpp" namespace teachos::arch::context_switching::descriptor_table { - typedef stl::vector global_descriptor_table; - auto create_global_descriptor_table() -> global_descriptor_table; auto initialize_global_descriptor_table() -> global_descriptor_table; diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp index 0305bff..d4febe1 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp @@ -1,10 +1,15 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/stl/vector.hpp" + #include namespace teachos::arch::context_switching::descriptor_table { + typedef stl::vector global_descriptor_table; + /** * @brief Represents a pointer to the Global Descriptor Table (GDT). * @@ -13,10 +18,8 @@ namespace teachos::arch::context_switching::descriptor_table */ struct global_descriptor_table_pointer { - std::size_t table_length; ///< The size of the GDT in bytes. - - // TODO: Would rather use global_descriptor_table *, but circular dependency - uint64_t address; ///< Pointer to the GDT base address. + std::size_t table_length; ///< The size of the GDT in bytes. + global_descriptor_table * address; ///< Pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 06e2e8a..86b6c75 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -52,13 +52,13 @@ namespace teachos::arch::context_switching::descriptor_table private: // The order in private variables starts for the first variable being the rightmost bit. - std::bitset<16U> _limit_1 = {}; ///< First part of the limit field (0 - 15) - std::bitset<24U> _base_1 = {}; ///< First part of the base field (16 - 39) - access_byte _access = {}; ///< Access byte field (40 - 47) - std::bitset<4U> _limit_2 = {}; ///< Second part of the limit field (48 - 51) - gdt_flags _flag = {}; ///< Flags field (52 - 55) - std::bitset<40U> _base_2 = {}; ///< Second part of the base field (56 - 95) - uint32_t _reserved = {}; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + uint16_t _limit_1 = {}; ///< First part of the limit field (0 - 15) + std::bitset<24U> _base_1 = {}; ///< First part of the base field (16 - 39) + access_byte _access = {}; ///< Access byte field (40 - 47) + std::bitset<4U> _limit_2 = {}; ///< Second part of the limit field (48 - 51) + gdt_flags _flag = {}; ///< Flags field (52 - 55) + std::bitset<40U> _base_2 = {}; ///< Second part of the base field (56 - 95) + uint32_t _reserved = {}; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index ca3d7ff..f4ea61b 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -45,12 +45,9 @@ namespace teachos::arch::context_switching::descriptor_table auto initialize_global_descriptor_table() -> global_descriptor_table { - global_descriptor_table gdt{create_global_descriptor_table()}; - - // TODO: Second argument does not work yet (because pointer hpp) + decltype(auto) gdt = create_global_descriptor_table(); global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); - return gdt; } -} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp index cb13aa8..70a48dd 100644 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ b/arch/x86_64/src/kernel/cpu/lgdt.cpp @@ -4,11 +4,14 @@ namespace teachos::arch::kernel::cpu { - auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer gdt_pointer) + auto + load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void { // TODO: build lgdt argument from global_descriptor_table_pointer (don't know how yet) - asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); + // asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); + if (gdt_pointer.table_length) + { + } } - -} // namespace teachos::arch::kernel::cpu \ No newline at end of file +} // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 2b8e6e7e10f084a9a9ba5c0b79a041f4d1ac459b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 15 Mar 2025 11:29:26 +0000 Subject: implement loading of gdtr register --- arch/x86_64/CMakeLists.txt | 8 +- .../descriptor_table/access_byte.hpp | 67 +++++--- .../descriptor_table/gdt_flags.hpp | 25 ++- .../global_descriptor_table_pointer.hpp | 22 ++- .../descriptor_table/segment_descriptor.hpp | 16 +- .../descriptor_table/type_field.hpp | 84 --------- arch/x86_64/include/arch/kernel/cpu/lgdt.hpp | 11 +- .../arch/memory/allocator/physical_frame.hpp | 6 +- .../arch/memory/heap/linked_list_allocator.hpp | 4 +- .../arch/memory/multiboot/elf_symbols_section.hpp | 6 +- .../include/arch/memory/multiboot/memory_map.hpp | 6 +- .../include/arch/memory/paging/virtual_page.hpp | 2 +- arch/x86_64/include/arch/shared/container.hpp | 83 --------- .../arch/shared/contiguous_pointer_iterator.hpp | 190 --------------------- .../include/arch/shared/forward_value_iterator.hpp | 110 ------------ arch/x86_64/include/arch/shared/mutex.hpp | 57 ------- arch/x86_64/include/arch/stl/container.hpp | 83 +++++++++ .../arch/stl/contiguous_pointer_iterator.hpp | 190 +++++++++++++++++++++ .../include/arch/stl/forward_value_iterator.hpp | 110 ++++++++++++ arch/x86_64/include/arch/stl/mutex.hpp | 57 +++++++ .../descriptor_table/access_byte.cpp | 10 +- .../descriptor_table/gdt_flags.cpp | 14 +- .../descriptor_table/global_descriptor_table.cpp | 40 +++-- .../global_descriptor_table_pointer.cpp | 12 ++ .../descriptor_table/segment_descriptor.cpp | 17 +- .../descriptor_table/type_field.cpp | 12 -- arch/x86_64/src/kernel/cpu/lgdt.cpp | 13 +- arch/x86_64/src/kernel/cpu/ss.cpp | 8 +- arch/x86_64/src/kernel/main.cpp | 13 +- .../src/memory/heap/linked_list_allocator.cpp | 2 +- arch/x86_64/src/shared/mutex.cpp | 16 -- arch/x86_64/src/stl/mutex.cpp | 16 ++ 32 files changed, 639 insertions(+), 671 deletions(-) delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp delete mode 100644 arch/x86_64/include/arch/shared/container.hpp delete mode 100644 arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp delete mode 100644 arch/x86_64/include/arch/shared/forward_value_iterator.hpp delete mode 100644 arch/x86_64/include/arch/shared/mutex.hpp create mode 100644 arch/x86_64/include/arch/stl/container.hpp create mode 100644 arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp create mode 100644 arch/x86_64/include/arch/stl/forward_value_iterator.hpp create mode 100644 arch/x86_64/include/arch/stl/mutex.hpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/type_field.cpp delete mode 100644 arch/x86_64/src/shared/mutex.cpp create mode 100644 arch/x86_64/src/stl/mutex.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 53339d2..912daf6 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -65,11 +65,11 @@ target_sources("_memory" PRIVATE ) #[============================================================================[ -# The Shared Library +# The STL Library #]============================================================================] -target_sources("_shared" PRIVATE - "src/shared/mutex.cpp" +target_sources("_stl" PRIVATE + "src/stl/mutex.cpp" ) #[============================================================================[ @@ -91,8 +91,8 @@ target_sources("_context" PRIVATE "src/context_switching/descriptor_table/access_byte.cpp" "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/global_descriptor_table.cpp" + "src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp" "src/context_switching/descriptor_table/segment_descriptor.cpp" - "src/context_switching/descriptor_table/type_field.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index dc4de03..bafce8d 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -2,9 +2,8 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP -#include "arch/context_switching/descriptor_table/type_field.hpp" - #include +#include namespace teachos::arch::context_switching::descriptor_table { @@ -12,24 +11,49 @@ namespace teachos::arch::context_switching::descriptor_table * @brief Defines helper function for all states that the access byte field of a segment descriptor can * have. */ - struct access_byte + struct [[gnu::packed]] access_byte { /** * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. */ enum bitset : uint8_t { - CODE_OR_DATA_SEGMENT = 1U << 0U, ///< Defines a system segment (if 0) or a code/data segment (if 1). - ACCESS_LEVEL_KERNEL = 0, ///< Highest privileged level used by the kernel to allow for full access of resources. + 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). + ACCESS_LEVEL_KERNEL = + 0U << 4U, ///< Highest privileged level used by the kernel to allow for full access of resources. ACCESS_LEVEL_ADMIN = - 2, ///< 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. + 2U << 4U, ///< 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. ACCESS_LEVEL_PRIVILEGED_USER = - 4, ///< 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. - ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. - PRESENT = 1U << 3U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. + 4U << 4U, ///< 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. + ACCESS_LEVEL_USER = 6U << 4U, ///< Restricts access to only application and their specific memory. + PRESENT = 1U << 3U << 4U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. }; /** @@ -40,10 +64,11 @@ namespace teachos::arch::context_switching::descriptor_table /** * @brief Constructor. * - * @param flags Left-most four bits of the access_byte. - * @param type_field Right-most four bits of the access_byte representing the type_field. + * @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, uint8_t type_field); + access_byte(uint8_t flags); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -54,14 +79,7 @@ namespace teachos::arch::context_switching::descriptor_table * @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<4U> other) const -> bool; - - /** - * @brief Returns the type field of the access byte. - * - * @return Copy of the underlying type field bits. - */ - auto get_type_field() const -> type_field; + auto contains_flags(std::bitset<8U> other) const -> bool; /** * @brief Allows to compare the underlying std::bitset of two instances. @@ -72,8 +90,7 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(access_byte const & other) const -> bool = default; private: - std::bitset<4U> _flags = {}; ///< Underlying bitset used to read the flags from. - type_field _type = {}; ///< Field specifying the type of the segment descriptor and its settings. + uint8_t _flags = {}; ///< Underlying bitset used to read the flags from. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index f27284e..11f5dd4 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -11,7 +11,7 @@ namespace teachos::arch::context_switching::descriptor_table * @brief Defines helper function for all states that the flags field of a segment descriptor can * have. */ - struct gdt_flags + struct [[gnu::packed]] gdt_flags { /** * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. @@ -40,11 +40,14 @@ namespace teachos::arch::context_switching::descriptor_table /** * @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. Only the rightmost 3 bit of the value will actually be - * converted into the std::bitset, because the leftmost 4 bit are irrelevant and the 4th bit is reserved. + * @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); + gdt_flags(uint8_t flags, std::bitset<20U> limit); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -57,6 +60,15 @@ namespace teachos::arch::context_switching::descriptor_table */ 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 std::bitset of two instances. * @@ -66,7 +78,8 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(gdt_flags const & other) const -> bool = default; private: - std::bitset<4U> _flags = {}; ///< Underlying bitset used to read the flags from. + uint8_t _limit_2 : 4 = {}; + uint8_t _flags : 4 = {}; ///< Underlying bitset used to read the flags from. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp index d4febe1..ed17be3 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp @@ -16,10 +16,26 @@ namespace teachos::arch::context_switching::descriptor_table * 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 global_descriptor_table_pointer + struct [[gnu::packed]] global_descriptor_table_pointer { - std::size_t table_length; ///< The size of the GDT in bytes. - global_descriptor_table * address; ///< Pointer to the GDT base address. + /** + * @brief Default constructor. + */ + global_descriptor_table_pointer() = default; + + /** + * @brief Constructor. + */ + global_descriptor_table_pointer(uint16_t table_length, global_descriptor_table * 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. + global_descriptor_table * address = {}; ///< Non-owning pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 86b6c75..7106771 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -4,7 +4,6 @@ #include "arch/context_switching/descriptor_table/access_byte.hpp" #include "arch/context_switching/descriptor_table/gdt_flags.hpp" #include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" -#include "arch/context_switching/descriptor_table/type_field.hpp" namespace teachos::arch::context_switching::descriptor_table { @@ -14,7 +13,7 @@ namespace teachos::arch::context_switching::descriptor_table /** * @brief Defines helper function for all states and the actual data the segment descriptor can have. */ - struct segment_descriptor + struct [[gnu::packed]] segment_descriptor { /** * @brief Default Constructor. @@ -52,13 +51,12 @@ namespace teachos::arch::context_switching::descriptor_table 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) - std::bitset<24U> _base_1 = {}; ///< First part of the base field (16 - 39) - access_byte _access = {}; ///< Access byte field (40 - 47) - std::bitset<4U> _limit_2 = {}; ///< Second part of the limit field (48 - 51) - gdt_flags _flag = {}; ///< Flags field (52 - 55) - std::bitset<40U> _base_2 = {}; ///< Second part of the base field (56 - 95) - uint32_t _reserved = {}; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + 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) + uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 95) + uint32_t _reserved = {}; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp deleted file mode 100644 index 3822f9c..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP - -#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" - -#include - -namespace teachos::arch::context_switching::descriptor_table -{ - /** - * @brief Defines helper function for all states that the flags field of a segment descriptor can - * have. - */ - struct type_field - { - /** - * @brief Possible set bits in our underlying std::bitset 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. - }; - - /** - * @brief Default Constructor. - */ - type_field() = default; - - /** - * @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. - */ - type_field(uint8_t flags); - - /** - * @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<4U> 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==(type_field const & other) const -> bool = default; - - private: - std::bitset<4U> _flags = {}; ///< Underlying bitset used to read the flags from. - }; -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp b/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp index 633d460..85e2949 100644 --- a/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp @@ -8,10 +8,19 @@ 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::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::descriptor_table::global_descriptor_table_pointer gdt_pointer) + auto + load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void; } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 7f04042..7ea5517 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -1,8 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP -#include "arch/shared/container.hpp" -#include "arch/shared/forward_value_iterator.hpp" +#include "arch/stl/container.hpp" +#include "arch/stl/forward_value_iterator.hpp" #include #include @@ -79,7 +79,7 @@ namespace teachos::arch::memory::allocator {}; ///< Index number of the current physical frame, used to distinguish it from other frames. }; - typedef shared::container> frame_container; + typedef stl::container> frame_container; } // namespace teachos::arch::memory::allocator 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 df9e370..da3c8ff 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,7 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/heap/memory_block.hpp" -#include "arch/shared/mutex.hpp" +#include "arch/stl/mutex.hpp" namespace teachos::arch::memory::heap { @@ -114,7 +114,7 @@ namespace teachos::arch::memory::heap std::size_t heap_start; ///< Start of the allocatable heap area. std::size_t heap_end; ///< End of the allocatable heap area. memory_block * first; ///< First free entry in our memory. - shared::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. + stl::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. }; extern linked_list_allocator kernel_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 e8f6b0a..4c7470b 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 @@ -2,8 +2,8 @@ #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP #include "arch/memory/multiboot/info.hpp" -#include "arch/shared/container.hpp" -#include "arch/shared/contiguous_pointer_iterator.hpp" +#include "arch/stl/container.hpp" +#include "arch/stl/contiguous_pointer_iterator.hpp" #include #include @@ -162,7 +162,7 @@ namespace teachos::arch::memory::multiboot ///< contained in the section, to ensure byte alignment is actually 4 byte. }; - typedef shared::container> elf_section_header_container; + typedef stl::container> elf_section_header_container; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index c28c986..cc8db8c 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -2,8 +2,8 @@ #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP #include "arch/memory/multiboot/info.hpp" -#include "arch/shared/container.hpp" -#include "arch/shared/contiguous_pointer_iterator.hpp" +#include "arch/stl/container.hpp" +#include "arch/stl/contiguous_pointer_iterator.hpp" #include @@ -46,7 +46,7 @@ namespace teachos::arch::memory::multiboot struct memory_area entries; ///< Specific memory regions. }; - typedef shared::container> memory_area_container; + typedef stl::container> memory_area_container; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index d820e82..d9164a0 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -84,7 +84,7 @@ namespace teachos::arch::memory::paging {}; ///< Index number of the current virtual page, used to distinguish it from other pages. }; - typedef shared::container> page_container; + typedef stl::container> page_container; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/shared/container.hpp b/arch/x86_64/include/arch/shared/container.hpp deleted file mode 100644 index f2fd1dc..0000000 --- a/arch/x86_64/include/arch/shared/container.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP -#define TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP - -#include - -namespace teachos::arch::shared -{ - /** - * @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. - */ - 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. - */ - 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. - */ - 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 - */ - 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::shared - -#endif // TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP diff --git a/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp b/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp deleted file mode 100644 index e2520dc..0000000 --- a/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp +++ /dev/null @@ -1,190 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP -#define TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP - -#include - -namespace teachos::arch::shared -{ - /** - * @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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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::shared - -#endif // TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/shared/forward_value_iterator.hpp b/arch/x86_64/include/arch/shared/forward_value_iterator.hpp deleted file mode 100644 index c5dfc06..0000000 --- a/arch/x86_64/include/arch/shared/forward_value_iterator.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP -#define TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP - -#include - -namespace teachos::arch::shared -{ - /** - * @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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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::shared - -#endif // TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/shared/mutex.hpp b/arch/x86_64/include/arch/shared/mutex.hpp deleted file mode 100644 index b18a8b3..0000000 --- a/arch/x86_64/include/arch/shared/mutex.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP -#define TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP - -#include - -namespace teachos::arch::shared -{ - /** - * @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). - */ - auto lock() -> void; - - /** - * @brief Try to lock the mutex (non-blocking). - * - * @return True if lock has been acquired and false otherwise. - */ - auto try_lock() -> bool; - - /** - * @brief Unlock the mutex. - */ - auto unlock() -> void; - - private: - std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. - }; - -} // namespace teachos::arch::shared - -#endif // TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP diff --git a/arch/x86_64/include/arch/stl/container.hpp b/arch/x86_64/include/arch/stl/container.hpp new file mode 100644 index 0000000..b0f513b --- /dev/null +++ b/arch/x86_64/include/arch/stl/container.hpp @@ -0,0 +1,83 @@ +#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. + */ + 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. + */ + 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. + */ + 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 + */ + 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 new file mode 100644 index 0000000..d15d2e2 --- /dev/null +++ b/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp @@ -0,0 +1,190 @@ +#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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + auto operator<=>(contiguous_pointer_iterator const & other) const -> std::strong_ordering = default; + + private: + pointer_type ptr = + {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. + }; + +} // namespace teachos::arch::stl + +#endif // TEACHOS_ARCH_X86_64_STL_CONTIGUOUS_POINTER_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/stl/forward_value_iterator.hpp b/arch/x86_64/include/arch/stl/forward_value_iterator.hpp new file mode 100644 index 0000000..7c30964 --- /dev/null +++ b/arch/x86_64/include/arch/stl/forward_value_iterator.hpp @@ -0,0 +1,110 @@ +#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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + auto operator==(forward_value_iterator const & other) const -> bool = default; + + private: + value_type value = + {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. + }; + +} // namespace teachos::arch::stl + +#endif // TEACHOS_ARCH_X86_64_STL_FORWARD_VALUE_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/stl/mutex.hpp b/arch/x86_64/include/arch/stl/mutex.hpp new file mode 100644 index 0000000..d8fd9dc --- /dev/null +++ b/arch/x86_64/include/arch/stl/mutex.hpp @@ -0,0 +1,57 @@ +#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). + */ + auto lock() -> void; + + /** + * @brief Try to lock the mutex (non-blocking). + * + * @return True if lock has been acquired and false otherwise. + */ + auto try_lock() -> bool; + + /** + * @brief Unlock the mutex. + */ + auto unlock() -> void; + + private: + std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. + }; + +} // namespace teachos::arch::stl + +#endif // TEACHOS_ARCH_X86_64_STL_MUTEX_HPP diff --git a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp index 4e5459f..6b54451 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp @@ -2,14 +2,14 @@ namespace teachos::arch::context_switching::descriptor_table { - access_byte::access_byte(uint8_t flags, uint8_t type_field) + access_byte::access_byte(uint8_t flags) : _flags(flags) - , _type(type_field) { // Nothing to do. } - auto access_byte::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } - - auto access_byte::get_type_field() const -> type_field { return _type; } + auto access_byte::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp index 65f2e90..9e95182 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp @@ -1,14 +1,18 @@ #include "arch/context_switching/descriptor_table/gdt_flags.hpp" -#include "arch/exception_handling/assert.hpp" - namespace teachos::arch::context_switching::descriptor_table { - gdt_flags::gdt_flags(uint8_t flags) - : _flags(flags) + gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) + : _limit_2(limit.to_ulong() >> 16U) + , _flags(flags) { // Nothing to do. } - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool + { + return (std::bitset<4U>{_flags} & other) == other; + } + + auto descriptor_table::gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index f4ea61b..c5554a7 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -1,6 +1,7 @@ #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" #include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/lgdt.hpp" #include "arch/stl/vector.hpp" @@ -10,33 +11,32 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor null_segment{0}; + std::bitset<20U> limit{0xFFFFF}; // Kernel space code segment access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::CODE_SEGMENT | type_field::READABLE}; - gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; - segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, 0xFFFFF}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | + access_byte::READABLE}; + gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; + segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, limit}; // Kernel space data segment access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::WRITABLE}; - gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; - segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, 0xFFFFF}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; + gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; + segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, limit}; // User space code segment access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::CODE_SEGMENT | type_field::READABLE}; - gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; - segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, 0xFFFFF}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | + access_byte::READABLE}; + gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; + segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, limit}; // User space data segment access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::WRITABLE}; - gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; - segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, 0xFFFFF}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; + gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; + segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, limit}; stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, user_code_segment, user_data_segment}; @@ -46,8 +46,14 @@ namespace teachos::arch::context_switching::descriptor_table auto initialize_global_descriptor_table() -> global_descriptor_table { decltype(auto) gdt = create_global_descriptor_table(); - global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; + global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); + + auto stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + arch::exception_handling::assert( + gdt_pointer == stored_gdt_pointer, + "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + return gdt; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp new file mode 100644 index 0000000..f552496 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp @@ -0,0 +1,12 @@ +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, + global_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp index a743ad2..c1a46a6 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -5,9 +5,8 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor::segment_descriptor(uint128_t flags) : _limit_1(flags << 112U) , _base_1((flags >> 16U) << 88U) - , _access((flags >> 44U) << 80U, (flags >> 40U) << 84U) - , _limit_2((flags >> 48U) << 72U) - , _flag((flags >> 52U) << 72U) + , _access((flags >> 40U) << 80U) + , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) , _base_2((flags >> 56U) << 32U) , _reserved(flags >> 96U) { @@ -16,10 +15,9 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit) - : _limit_1((limit.to_ulong() << 4U) >> 16U) + : _limit_1(limit.to_ulong()) , _base_1((base << 40U) >> 40U) , _access(access_byte) - , _limit_2(limit.to_ulong() >> 16U) , _flag(flags) , _base_2(base >> 24U) , _reserved(0U) @@ -33,12 +31,7 @@ namespace teachos::arch::context_switching::descriptor_table { return segment_descriptor_type::SYSTEM_SEGMENT; } - - if (_access.get_type_field().contains_flags(type_field::CODE_SEGMENT)) - { - return segment_descriptor_type::CODE_SEGMENT; - } - - return segment_descriptor_type::DATA_SEGMENT; + return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp b/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp deleted file mode 100644 index d967a97..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "arch/context_switching/descriptor_table/type_field.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - type_field::type_field(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto type_field::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp index 70a48dd..386914f 100644 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ b/arch/x86_64/src/kernel/cpu/lgdt.cpp @@ -4,14 +4,17 @@ namespace teachos::arch::kernel::cpu { + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; + asm("sgdt %[output]" : [output] "=m"(current_value)); + return current_value; + } + auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void { - // TODO: build lgdt argument from global_descriptor_table_pointer (don't know how yet) - // asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); - if (gdt_pointer.table_length) - { - } + asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp index 9c8dd61..1f28e7f 100644 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -19,15 +19,15 @@ namespace teachos::arch::kernel::cpu auto read_ss() -> uint16_t { - uint16_t ss; - asm volatile("mov %%ss, %0" : "=r"(ss)); - return ss; + uint16_t segment_selector; + asm volatile("mov %%ss, %[output]" : [output] "=r"(segment_selector)); + return segment_selector; } auto write_ss(segment_selector selector) -> void { uint16_t ss = selector.to_uint16(); - asm volatile("mov %0, %%ss" ::"r"(ss)); + asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "r"(ss)); } } // namespace teachos::arch::kernel::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 4db9599..2c0b6c8 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/kernel/cpu/lgdt.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,16 +61,8 @@ namespace teachos::arch::kernel heap_test(); - context_switching::descriptor_table::global_descriptor_table global_descriptor_table{ - context_switching::descriptor_table::initialize_global_descriptor_table()}; - - decltype(auto) x = global_descriptor_table.at(1); - if (global_descriptor_table.size() == 0) - { - } - if (x.get_segment_type() == context_switching::descriptor_table::segment_descriptor_type::CODE_SEGMENT) - { - } + auto global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + (void)global_descriptor_table.at(1); video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index a824c8a..5101ab2 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -11,7 +11,7 @@ namespace teachos::arch::memory::heap : heap_start(heap_start) , heap_end(heap_end) , first(nullptr) - , mutex{shared::mutex{}} + , mutex{stl::mutex{}} { auto const heap_size = heap_end - heap_start; exception_handling::assert( diff --git a/arch/x86_64/src/shared/mutex.cpp b/arch/x86_64/src/shared/mutex.cpp deleted file mode 100644 index 6598255..0000000 --- a/arch/x86_64/src/shared/mutex.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/shared/mutex.hpp" - -namespace teachos::arch::shared -{ - auto mutex::lock() -> void - { - while (!try_lock()) - { - // Nothing to do - } - } - - auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } - - auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } -} // namespace teachos::arch::shared diff --git a/arch/x86_64/src/stl/mutex.cpp b/arch/x86_64/src/stl/mutex.cpp new file mode 100644 index 0000000..232a11c --- /dev/null +++ b/arch/x86_64/src/stl/mutex.cpp @@ -0,0 +1,16 @@ +#include "arch/stl/mutex.hpp" + +namespace teachos::arch::stl +{ + auto mutex::lock() -> void + { + while (!try_lock()) + { + // Nothing to do + } + } + + auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } + + auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } +} // namespace teachos::arch::stl -- cgit v1.2.3 From e6a9d939ed5e9f89e69efdacc60a1ce6edd1061c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 15 Mar 2025 12:38:11 +0000 Subject: temporarily make all page table entries user accessible --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 1de31b5..ef4fe61 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -22,7 +22,7 @@ namespace teachos::arch::memory::paging 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_ACCESIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code. + 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. diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 5aa0982..3a0f03f 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging } // namespace entry::entry(uint64_t flags) - : flags(flags) + : flags(flags | entry::USER_ACCESSIBLE) // TODO: Temporarily make all entries user accessible { // Nothing to do. } @@ -21,14 +21,19 @@ namespace teachos::arch::memory::paging { flags |= entry::PRESENT; } + if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) { flags |= entry::WRITABLE; } + if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) { flags |= entry::EXECUTING_CODE_FORBIDDEN; } + + // TODO: Temporarily make all entries user accessible + flags |= entry::USER_ACCESSIBLE; } auto entry::is_unused() const -> bool { return flags == 0U; } @@ -51,7 +56,9 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = frame.start_address() | additional_flags.to_ulong(); + + // TODO: Temporarily make all entries user accessible + flags = frame.start_address() | additional_flags.to_ulong() | entry::USER_ACCESSIBLE; } auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } -- cgit v1.2.3 From 5a332c90f79e6d10de1a8cd478c4dbef82f4d74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 15 Mar 2025 14:48:29 +0000 Subject: Use empty bit field to implement reserved --- .../arch/context_switching/descriptor_table/segment_descriptor.hpp | 2 +- .../src/context_switching/descriptor_table/segment_descriptor.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 7106771..7454470 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -56,7 +56,7 @@ namespace teachos::arch::context_switching::descriptor_table access_byte _access = {}; ///< Access byte field (40 - 47) gdt_flags _flag = {}; ///< Second part of the limit field + Flags field (48 - 55) uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 95) - uint32_t _reserved = {}; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp index c1a46a6..3e93823 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -8,7 +8,6 @@ namespace teachos::arch::context_switching::descriptor_table , _access((flags >> 40U) << 80U) , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) , _base_2((flags >> 56U) << 32U) - , _reserved(flags >> 96U) { // Nothing to do. } @@ -20,7 +19,6 @@ namespace teachos::arch::context_switching::descriptor_table , _access(access_byte) , _flag(flags) , _base_2(base >> 24U) - , _reserved(0U) { // Nothing to do } -- cgit v1.2.3 From ecb67842d3578dfc8c7d685b0cd168efd24505e6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 15 Mar 2025 14:56:12 +0000 Subject: create TSS descriptor --- .../descriptor_table/global_descriptor_table.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index c5554a7..6474739 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -12,6 +12,7 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor null_segment{0}; std::bitset<20U> limit{0xFFFFF}; + // Kernel space code segment access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | @@ -38,6 +39,15 @@ namespace teachos::arch::context_switching::descriptor_table gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, limit}; + // Task state segment + // TODO: Create TSS + access_byte tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::TASK_STATE_SEGMENT_AVAILABLE}; + gdt_flags tss_gdt_flags{0U, limit}; + uint64_t tss_address = 0; // &TSS + uint64_t tss_limit = 0U; // sizeof(TSS) - 1 + segment_descriptor task_state_segment{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, user_code_segment, user_data_segment}; return global_descriptor_table; -- cgit v1.2.3 From 36758071881088b27a52cee4e5653f6cf6a79a78 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 16 Mar 2025 12:41:09 +0000 Subject: start implementing TSS --- arch/x86_64/CMakeLists.txt | 3 +- .../descriptor_table/global_descriptor_table.hpp | 42 ++++++++ .../descriptor_table/task_state_segment.hpp | 39 ++++++++ arch/x86_64/include/arch/kernel/cpu/gdtr.hpp | 28 ++++++ arch/x86_64/include/arch/kernel/cpu/lgdt.hpp | 28 ------ arch/x86_64/include/arch/kernel/cpu/tr.hpp | 26 +++++ .../descriptor_table/global_descriptor_table.cpp | 108 ++++++++++++++------- arch/x86_64/src/kernel/cpu/gdtr.cpp | 20 ++++ arch/x86_64/src/kernel/cpu/lgdt.cpp | 20 ---- arch/x86_64/src/kernel/cpu/tr.cpp | 17 ++++ arch/x86_64/src/kernel/main.cpp | 1 - 11 files changed, 245 insertions(+), 87 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/gdtr.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/lgdt.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/tr.hpp create mode 100644 arch/x86_64/src/kernel/cpu/gdtr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/lgdt.cpp create mode 100644 arch/x86_64/src/kernel/cpu/tr.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 912daf6..aad7951 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -8,10 +8,11 @@ mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT) target_sources("_kernel" PRIVATE "src/kernel/main.cpp" "src/kernel/cpu/control_register.cpp" - "src/kernel/cpu/lgdt.cpp" + "src/kernel/cpu/gdtr.cpp" "src/kernel/cpu/msr.cpp" "src/kernel/cpu/ss.cpp" "src/kernel/cpu/tlb.cpp" + "src/kernel/cpu/tr.cpp" ) target_link_options("_kernel" PRIVATE diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp index c4d0e30..ab8f1ac 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp @@ -2,12 +2,54 @@ #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP #include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/descriptor_table/task_state_segment.hpp" namespace teachos::arch::context_switching::descriptor_table { + enum class access_level + { + KERNEL, + USER + }; + + /** + * @brief Creates a generic segment_descriptor from the passed arguments. + * + * @param segment_descriptor_type Defines the type of the segment descriptor. + * @param access_level Defines the segment descriptor access level (KERNEL or USER). + * @return Created segment_descriptor. + */ + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) + -> segment_descriptor; + + /** + * @brief Creates a global_descriptor_table on the heap and fills it with the following segment registers: + * + * - Kernel Code Segment + * - Kernel Data Segment + * - User Code Segment + * - User Data Segment + * + * @return Created global_descriptor_table. + */ auto create_global_descriptor_table() -> global_descriptor_table; + /** + * @brief Creates a task_state_segment segment_descriptor on the heap. + * + * @param tss task_state_segment whose pointer is used in the segment_descriptor + * @return Created segment_descriptor. + */ + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor; + + /** + * @brief Initializes the global_descriptor_table and task_state_segment by loading them + * in the GDTR and TR registers respectively. + * + * @return Created global_descriptor_table. + */ auto initialize_global_descriptor_table() -> global_descriptor_table; + } // namespace teachos::arch::context_switching::descriptor_table #endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp new file mode 100644 index 0000000..af7ae7c --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp @@ -0,0 +1,39 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief 64-bit task state segment + */ + struct [[gnu::packed]] task_state_segment + { + private: + uint16_t io_map_base_address = {}; + + uint16_t reserved_1 = {}; + uint32_t reserved_2 = {}; + uint32_t reserved_3 = {}; + + uint64_t ist7 = {}; + uint64_t ist6 = {}; + uint64_t ist5 = {}; + uint64_t ist4 = {}; + uint64_t ist3 = {}; + uint64_t ist2 = {}; + uint64_t ist1 = {}; + + uint32_t reserved_4 = {}; + uint32_t reserved_5 = {}; + + uint64_t rsp2 = {}; + uint64_t rsp1 = {}; + uint64_t rsp0 = {}; + + uint32_t reserved_6 = {}; + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp new file mode 100644 index 0000000..f9220b9 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp @@ -0,0 +1,28 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP + +#include "arch/context_switching/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::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::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/lgdt.hpp b/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp deleted file mode 100644 index 85e2949..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP - -#include "arch/context_switching/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::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::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) - -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/include/arch/kernel/cpu/tr.hpp new file mode 100644 index 0000000..5f99472 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/tr.hpp @@ -0,0 +1,26 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP + +#include "arch/context_switching/descriptor_table/task_state_segment.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 tss_pointer 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/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index 6474739..2b399f8 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -1,61 +1,87 @@ #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" #include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/descriptor_table/task_state_segment.hpp" #include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/lgdt.hpp" +#include "arch/kernel/cpu/gdtr.hpp" +#include "arch/kernel/cpu/tr.hpp" #include "arch/stl/vector.hpp" namespace teachos::arch::context_switching::descriptor_table { + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) + -> segment_descriptor + { + uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; + if (access_level == access_level::KERNEL) + { + access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; + } + else if (access_level == access_level::USER) + { + access_level_bitset = access_byte::ACCESS_LEVEL_USER; + } + + uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::LENGTH; + access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::UPPER_BOUND; + access_level_bitset |= access_byte::WRITABLE; + } + + std::bitset<20U> limit{0xFFFFF}; + access_byte access_byte{access_level_bitset}; + gdt_flags gdt_flags{gdt_flags_bitset, limit}; + segment_descriptor code_segment{access_byte, gdt_flags, 0, limit}; + + return code_segment; + } + auto create_global_descriptor_table() -> global_descriptor_table { segment_descriptor null_segment{0}; + segment_descriptor kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); + segment_descriptor kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); + segment_descriptor user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); + segment_descriptor user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - std::bitset<20U> limit{0xFFFFF}; + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; + return global_descriptor_table; + } - // Kernel space code segment - access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | - access_byte::READABLE}; - gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; - segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, limit}; - - // Kernel space data segment - access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; - gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; - segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, limit}; - - // User space code segment - access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | - access_byte::READABLE}; - gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; - segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, limit}; - - // User space data segment - access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; - gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; - segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, limit}; - - // Task state segment - // TODO: Create TSS + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor + { + std::bitset<20U> limit{0xFFFFF}; access_byte tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | access_byte::TASK_STATE_SEGMENT_AVAILABLE}; gdt_flags tss_gdt_flags{0U, limit}; - uint64_t tss_address = 0; // &TSS - uint64_t tss_limit = 0U; // sizeof(TSS) - 1 - segment_descriptor task_state_segment{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; + uint64_t tss_address = reinterpret_cast(tss); + constexpr uint64_t tss_limit = sizeof(task_state_segment) - 1; + segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; - stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; - return global_descriptor_table; + return tss_descriptor; } auto initialize_global_descriptor_table() -> global_descriptor_table { - decltype(auto) gdt = create_global_descriptor_table(); + auto gdt = create_global_descriptor_table(); + + // Add TSS segment descriptor to GDT + auto tss = new task_state_segment(); + auto tss_descriptor = create_task_state_segment_descriptor(tss); + gdt.push_back(tss_descriptor); + + // Load GDT into GDTR global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); @@ -64,6 +90,14 @@ namespace teachos::arch::context_switching::descriptor_table gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + // Load Task Register (LTR) using the index of TSS descriptor + uint16_t tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); + kernel::cpu::load_task_register(tss_selector); + + auto stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + return gdt; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/gdtr.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp new file mode 100644 index 0000000..2fe3a99 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/gdtr.cpp @@ -0,0 +1,20 @@ +#include "arch/kernel/cpu/gdtr.hpp" + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; + asm("sgdt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto + load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) + -> void + { + asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp deleted file mode 100644 index 386914f..0000000 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/kernel/cpu/lgdt.hpp" - -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer - { - context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; - asm("sgdt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto - load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) - -> void - { - asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp new file mode 100644 index 0000000..a28b9fc --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -0,0 +1,17 @@ +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_task_register() -> uint16_t + { + uint16_t current_value{}; + asm("str %[output]" : [output] "=m"(current_value)); + return current_value; + } + + // TODO: Is this really correct? + auto load_task_register(uint16_t gdt_offset) -> void + { + asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 2c0b6c8..c1e134a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,7 +1,6 @@ #include "arch/kernel/main.hpp" #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" -#include "arch/kernel/cpu/lgdt.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" -- cgit v1.2.3 From 37cb71ca7771a28835e3ed6aa5ed0797c9ba50fa Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 16 Mar 2025 12:50:14 +0000 Subject: add comment --- arch/x86_64/include/arch/kernel/cpu/tr.hpp | 2 +- arch/x86_64/src/kernel/cpu/tr.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/include/arch/kernel/cpu/tr.hpp index 5f99472..562fab7 100644 --- a/arch/x86_64/include/arch/kernel/cpu/tr.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/tr.hpp @@ -17,7 +17,7 @@ namespace teachos::arch::kernel::cpu auto store_task_register() -> uint16_t; /** - * @brief Loads the tss_pointer into the task register (TR). + * @brief Loads the gdt offset to the tss segment descriptor into the task register (TR). */ auto load_task_register(uint16_t gdt_offset) -> void; diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index a28b9fc..ad38d09 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -9,7 +9,6 @@ namespace teachos::arch::kernel::cpu return current_value; } - // TODO: Is this really correct? auto load_task_register(uint16_t gdt_offset) -> void { asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); -- cgit v1.2.3 From 5d1fbaba03f411b93281ef6934166d897cd0713e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 16 Mar 2025 13:42:44 +0000 Subject: Move base value out into variable --- .../context_switching/descriptor_table/global_descriptor_table.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index 2b399f8..77bd3e9 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -34,10 +34,11 @@ namespace teachos::arch::context_switching::descriptor_table access_level_bitset |= access_byte::WRITABLE; } + uint64_t base = 0x0; std::bitset<20U> limit{0xFFFFF}; access_byte access_byte{access_level_bitset}; gdt_flags gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor code_segment{access_byte, gdt_flags, 0, limit}; + segment_descriptor code_segment{access_byte, gdt_flags, base, limit}; return code_segment; } @@ -54,8 +55,8 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; + global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; return global_descriptor_table; } -- cgit v1.2.3 From 1658665ff3343382bc2af14ea87642aec544a606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 16 Mar 2025 15:20:27 +0000 Subject: Adjust task state segment struct --- .../descriptor_table/task_state_segment.hpp | 35 +++++++++------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp index af7ae7c..c3b0233 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp @@ -11,28 +11,21 @@ namespace teachos::arch::context_switching::descriptor_table struct [[gnu::packed]] task_state_segment { private: - uint16_t io_map_base_address = {}; - - uint16_t reserved_1 = {}; - uint32_t reserved_2 = {}; - uint32_t reserved_3 = {}; - - uint64_t ist7 = {}; - uint64_t ist6 = {}; - uint64_t ist5 = {}; - uint64_t ist4 = {}; - uint64_t ist3 = {}; - uint64_t ist2 = {}; - uint64_t ist1 = {}; - - uint32_t reserved_4 = {}; - uint32_t reserved_5 = {}; - - uint64_t rsp2 = {}; - uint64_t rsp1 = {}; + uint32_t : 32; uint64_t rsp0 = {}; - - uint32_t reserved_6 = {}; + 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; + uint32_t : 32; + uint16_t io_map_base_address = {}; }; } // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From c56a8a74bc4e9662469db33a85c12586f202985a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 17 Mar 2025 09:38:39 +0000 Subject: Fix issue in vector --- .../descriptor_table/gdt_flags.hpp | 4 +- .../descriptor_table/global_descriptor_table.hpp | 6 +- .../descriptor_table/segment_descriptor.hpp | 8 +++ .../descriptor_table/task_state_segment.hpp | 4 +- arch/x86_64/include/arch/stl/vector.hpp | 73 ++++++++++++++++++---- .../descriptor_table/global_descriptor_table.cpp | 27 ++++---- arch/x86_64/src/kernel/cpu/tr.cpp | 4 +- arch/x86_64/src/kernel/main.cpp | 2 +- 8 files changed, 92 insertions(+), 36 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index 11f5dd4..de41762 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -70,10 +70,10 @@ namespace teachos::arch::context_switching::descriptor_table auto get_limit() const -> std::bitset<4U>; /** - * @brief Allows to compare the underlying std::bitset of two instances. + * @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 std::bitset of both types is the same. + * @return Whether the underlying set bits of both types are the same. */ auto operator==(gdt_flags const & other) const -> bool = default; diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp index ab8f1ac..75e1e9d 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp @@ -30,7 +30,7 @@ namespace teachos::arch::context_switching::descriptor_table * - User Code Segment * - User Data Segment * - * @return Created global_descriptor_table. + * @return Copy of the created global_descriptor_table. */ auto create_global_descriptor_table() -> global_descriptor_table; @@ -46,9 +46,9 @@ namespace teachos::arch::context_switching::descriptor_table * @brief Initializes the global_descriptor_table and task_state_segment by loading them * in the GDTR and TR registers respectively. * - * @return Created global_descriptor_table. + * @return Reference to the created global_descriptor_table. */ - auto initialize_global_descriptor_table() -> global_descriptor_table; + auto initialize_global_descriptor_table() -> global_descriptor_table &; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 7454470..8714eb8 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -49,6 +49,14 @@ namespace teachos::arch::context_switching::descriptor_table */ auto get_segment_type() const -> segment_descriptor_type; + /** + * @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 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) diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp index c3b0233..1e306af 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp @@ -24,9 +24,9 @@ namespace teachos::arch::context_switching::descriptor_table uint64_t ist6 = {}; uint64_t ist7 = {}; uint64_t : 64; - uint32_t : 32; + uint16_t : 16; uint16_t io_map_base_address = {}; }; } // namespace teachos::arch::context_switching::descriptor_table -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index 112af57..f3d41fd 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -162,13 +162,13 @@ namespace teachos::arch::stl */ void push_back(T const & value) { - _data[_size] = value; - _size++; - if (_size == _capacity) { reserve(_capacity * 2); } + + _data[_size] = value; + _size++; } /** @@ -182,13 +182,13 @@ namespace teachos::arch::stl */ void push_back(T && value) { - _data[_size] = std::move(value); - _size++; - if (_size == _capacity) { reserve(_capacity * 2); } + + _data[_size] = std::move(value); + _size++; } /** @@ -206,13 +206,13 @@ namespace teachos::arch::stl template auto emplace_back(Args &&... args) -> T & { - _data[_size] = T{std::forward(args)...}; - auto const index = _size++; - if (_size == _capacity) { reserve(_capacity * 2); } + + _data[_size] = T{std::forward(args)...}; + auto const index = _size++; return _data[index]; } @@ -254,6 +254,30 @@ namespace teachos::arch::stl */ T const * cbegin() const noexcept { 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. + */ + T * rbegin() noexcept { 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. + */ + T const * rbegin() const noexcept { 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. + */ + T const * crbegin() const noexcept { 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. @@ -278,6 +302,33 @@ namespace teachos::arch::stl */ T const * cend() const noexcept { 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. + */ + T * rend() noexcept { 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. + */ + T const * rend() const noexcept { 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. + */ + T const * crend() const noexcept { 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 @@ -320,7 +371,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T & back() { return *end(); } + T & back() { return *rbegin(); } /** * @brief Returns a reference to the last element in the container. Calling back on an empty container causes @@ -328,7 +379,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T const & back() const { return *end(); } + T const & back() const { return *rbegin(); } /** * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index 77bd3e9..21a76e8 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -54,9 +54,12 @@ namespace teachos::arch::context_switching::descriptor_table create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); segment_descriptor user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor tss_descriptor = create_task_state_segment_descriptor(tss); - global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; + global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; return global_descriptor_table; } @@ -67,20 +70,15 @@ namespace teachos::arch::context_switching::descriptor_table access_byte::TASK_STATE_SEGMENT_AVAILABLE}; gdt_flags tss_gdt_flags{0U, limit}; uint64_t tss_address = reinterpret_cast(tss); - constexpr uint64_t tss_limit = sizeof(task_state_segment) - 1; - segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; - + constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; + segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, TSS_LIMIT}; return tss_descriptor; } - auto initialize_global_descriptor_table() -> global_descriptor_table + auto initialize_global_descriptor_table() -> global_descriptor_table & { - auto gdt = create_global_descriptor_table(); - - // Add TSS segment descriptor to GDT - auto tss = new task_state_segment(); - auto tss_descriptor = create_task_state_segment_descriptor(tss); - gdt.push_back(tss_descriptor); + // Global Descriptor Table needs to be kept alive + static auto gdt = create_global_descriptor_table(); // Load GDT into GDTR global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; @@ -91,14 +89,13 @@ namespace teachos::arch::context_switching::descriptor_table gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - // Load Task Register (LTR) using the index of TSS descriptor - uint16_t tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); + // Calculate the offset of the gdt in bytes to the TSS descriptor + uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); kernel::cpu::load_task_register(tss_selector); auto stored_task_register = kernel::cpu::store_task_register(); arch::exception_handling::assert(tss_selector == stored_task_register, "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - return gdt; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index ad38d09..d0e037f 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -5,12 +5,12 @@ namespace teachos::arch::kernel::cpu auto store_task_register() -> uint16_t { uint16_t current_value{}; - asm("str %[output]" : [output] "=m"(current_value)); + asm("str %[output]" : [output] "=r"(current_value)); return current_value; } auto load_task_register(uint16_t gdt_offset) -> void { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); + asm volatile("ltr %[input]" : /* no output from call */ : [input] "r"(gdt_offset)); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c1e134a..da6d6d3 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -60,7 +60,7 @@ namespace teachos::arch::kernel heap_test(); - auto global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); (void)global_descriptor_table.at(1); video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 3c01f820a064f3120a46aa3afdd9f88ce9e00db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 17 Mar 2025 14:51:24 +0000 Subject: Debug and adjust load task register assembly call. WIP --- .../descriptor_table/global_descriptor_table.cpp | 42 ++++++++++------------ .../descriptor_table/segment_descriptor.cpp | 2 +- arch/x86_64/src/kernel/cpu/tr.cpp | 8 ++++- 3 files changed, 27 insertions(+), 25 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index 21a76e8..b338d9d 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -34,44 +34,41 @@ namespace teachos::arch::context_switching::descriptor_table access_level_bitset |= access_byte::WRITABLE; } - uint64_t base = 0x0; - std::bitset<20U> limit{0xFFFFF}; - access_byte access_byte{access_level_bitset}; - gdt_flags gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor code_segment{access_byte, gdt_flags, base, limit}; - + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + access_byte const access_byte{access_level_bitset}; + gdt_flags const gdt_flags{gdt_flags_bitset, limit}; + segment_descriptor const code_segment{access_byte, gdt_flags, base, limit}; return code_segment; } auto create_global_descriptor_table() -> global_descriptor_table { - segment_descriptor null_segment{0}; - segment_descriptor kernel_code_segment = + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); - segment_descriptor kernel_data_segment = + segment_descriptor const kernel_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); - segment_descriptor user_code_segment = + segment_descriptor const user_code_segment = create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); - segment_descriptor user_data_segment = + segment_descriptor const user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); - segment_descriptor tss_descriptor = create_task_state_segment_descriptor(tss); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; + global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; return global_descriptor_table; } auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor { - std::bitset<20U> limit{0xFFFFF}; - access_byte tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::TASK_STATE_SEGMENT_AVAILABLE}; - gdt_flags tss_gdt_flags{0U, limit}; - uint64_t tss_address = reinterpret_cast(tss); constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; - segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, TSS_LIMIT}; + access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::TASK_STATE_SEGMENT_AVAILABLE}; + gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; + segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), TSS_LIMIT}; return tss_descriptor; } @@ -80,11 +77,10 @@ namespace teachos::arch::context_switching::descriptor_table // Global Descriptor Table needs to be kept alive static auto gdt = create_global_descriptor_table(); - // Load GDT into GDTR global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); - auto stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); arch::exception_handling::assert( gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); @@ -93,7 +89,7 @@ namespace teachos::arch::context_switching::descriptor_table uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); kernel::cpu::load_task_register(tss_selector); - auto stored_task_register = kernel::cpu::store_task_register(); + auto const stored_task_register = kernel::cpu::store_task_register(); arch::exception_handling::assert(tss_selector == stored_task_register, "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); return gdt; diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp index 3e93823..2385c58 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -15,7 +15,7 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit) : _limit_1(limit.to_ulong()) - , _base_1((base << 40U) >> 40U) + , _base_1(base) , _access(access_byte) , _flag(flags) , _base_2(base >> 24U) diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index d0e037f..e281189 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -11,6 +11,12 @@ namespace teachos::arch::kernel::cpu auto load_task_register(uint16_t gdt_offset) -> void { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "r"(gdt_offset)); + // asm volatile("ltr %[input]" : /* no output from call */ : [input] "R"(gdt_offset)); + // https://www.scs.stanford.edu/05au-cs240c/lab/i386/s07_03.htm + asm volatile("mov %[input], %%ax\n" + "ltr %%ax\n" + : /* no output from call */ + : [input] "r"(gdt_offset) + : "ax"); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From fd557fb19c4ad25fbcb1368a73fddd91921496fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 18 Mar 2025 10:48:24 +0000 Subject: Fix invalid bit values in access byte and typo in create_segment_descriptor method --- .../arch/context_switching/descriptor_table/access_byte.hpp | 10 +++++----- .../descriptor_table/global_descriptor_table.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index bafce8d..646c2ca 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -44,15 +44,15 @@ namespace teachos::arch::context_switching::descriptor_table 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). ACCESS_LEVEL_KERNEL = - 0U << 4U, ///< Highest privileged level used by the kernel to allow for full access of resources. + 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. ACCESS_LEVEL_ADMIN = - 2U << 4U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + 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. ACCESS_LEVEL_PRIVILEGED_USER = - 4U << 4U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + 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. - ACCESS_LEVEL_USER = 6U << 4U, ///< Restricts access to only application and their specific memory. - PRESENT = 1U << 3U << 4U, ///< Present bit; Allows an entry to refer to a valid segment. + ACCESS_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. }; diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index b338d9d..578e264 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -19,7 +19,7 @@ namespace teachos::arch::context_switching::descriptor_table } else if (access_level == access_level::USER) { - access_level_bitset = access_byte::ACCESS_LEVEL_USER; + access_level_bitset |= access_byte::ACCESS_LEVEL_USER; } uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; -- cgit v1.2.3 From 7a98b1dcb1f4436664a8f1a5d6e71ab2c65378f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 18 Mar 2025 14:39:53 +0000 Subject: Attempt to add calls that Reload code segment and data segment register --- .../descriptor_table/global_descriptor_table.cpp | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index 578e264..dccce6b 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -94,4 +94,35 @@ namespace teachos::arch::context_switching::descriptor_table "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); return gdt; } + + auto reload_cs_register(uint16_t gdt_data_offset) -> void + { + asm volatile("mov %[input], %%ax\n" + "mov %%ax %%ds\n" // Data Segment + "mov %%ax %%es\n" // Extra Segment (used for string operations) + "mov %%ax %%fs\n" // General-purpose Segment + "mov %%ax %%gs\n" // General-purpose Segment + "mov %%ax %%ss\n" // Stack Segment + : /* no output from call */ + : [input] "r"(gdt_data_offset) + : "ax"); + } + + auto reload_segment_register(uint16_t gdt_code_offset, uint16_t gdt_data_offset) -> void + { + /* + Whatever you do with the GDT has no effect on the CPU until you load new Segment Selectors into Segment Registers. + For most of these registers, the process is as simple as using MOV instructions, but changing the CS register + requires code resembling a jump or call to elsewhere, as this is the only way its value is meant to be changed. + */ + auto function = [gdt_data_offset] { reload_cs_register(gdt_data_offset); }; + + asm volatile("push %[input]\n" + "lea %[func], %%rax\n" + "push %%rax\n" + "retfq\n" + : /* no output from call */ + : [input] "r"(gdt_code_offset), [func] "r"(&function) + : "rax"); + } } // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From b6ee8bec7ed23fd0c544f67f735e96b2bfe67682 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 20 Mar 2025 15:30:18 +0000 Subject: begin implementation of IDT --- arch/x86_64/CMakeLists.txt | 7 ++++ arch/x86_64/include/arch/boot/pointers.hpp | 5 +++ .../descriptor_table/gate_descriptor.hpp | 15 ++++++++ .../descriptor_table/initialization.hpp | 23 ++++++++++++ .../interrupt_descriptor_table.hpp | 14 ++++++++ .../interrupt_descriptor_table_pointer.hpp | 42 ++++++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/idtr.hpp | 27 ++++++++++++++ arch/x86_64/include/arch/kernel/cpu/if.hpp | 14 ++++++++ arch/x86_64/include/arch/kernel/cpu/jmp.hpp | 35 ++++++++++++++++++ arch/x86_64/src/boot/boot.s | 13 +++++++ .../descriptor_table/gate_descriptor.cpp | 5 +++ .../descriptor_table/global_descriptor_table.cpp | 42 ++-------------------- .../descriptor_table/initialization.cpp | 38 ++++++++++++++++++++ .../interrupt_descriptor_table.cpp | 10 ++++++ .../interrupt_descriptor_table_pointer.cpp | 13 +++++++ arch/x86_64/src/kernel/cpu/idtr.cpp | 19 ++++++++++ arch/x86_64/src/kernel/cpu/if.cpp | 5 +++ arch/x86_64/src/kernel/cpu/jmp.cpp | 16 +++++++++ arch/x86_64/src/kernel/main.cpp | 10 +++--- 19 files changed, 310 insertions(+), 43 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/idtr.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/if.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/jmp.hpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/initialization.cpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/src/kernel/cpu/idtr.cpp create mode 100644 arch/x86_64/src/kernel/cpu/if.cpp create mode 100644 arch/x86_64/src/kernel/cpu/jmp.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index aad7951..a435ef9 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -9,6 +9,9 @@ target_sources("_kernel" PRIVATE "src/kernel/main.cpp" "src/kernel/cpu/control_register.cpp" "src/kernel/cpu/gdtr.cpp" + "src/kernel/cpu/idtr.cpp" + "src/kernel/cpu/if.cpp" + "src/kernel/cpu/jmp.cpp" "src/kernel/cpu/msr.cpp" "src/kernel/cpu/ss.cpp" "src/kernel/cpu/tlb.cpp" @@ -90,9 +93,13 @@ target_sources("_exception" PRIVATE target_sources("_context" PRIVATE "src/context_switching/descriptor_table/access_byte.cpp" + "src/context_switching/descriptor_table/gate_descriptor.cpp" "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/global_descriptor_table.cpp" "src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp" + "src/context_switching/descriptor_table/initialization.cpp" + "src/context_switching/descriptor_table/interrupt_descriptor_table.cpp" + "src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp" "src/context_switching/descriptor_table/segment_descriptor.cpp" ) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index fe9c657..2a43f22 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -10,6 +10,11 @@ namespace teachos::arch::boot */ extern "C" size_t const multiboot_information_pointer; + /** + * @brief Address pointing to the start of the multiboot information structure. + */ + extern "C" size_t const segment_register_reload_pointer; + } // namespace teachos::arch::boot #endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp new file mode 100644 index 0000000..f410219 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp @@ -0,0 +1,15 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP + +namespace teachos::arch::context_switching::descriptor_table +{ + struct [[gnu::packed]] gate_descriptor + { + /** + * @brief Default Constructor. + */ + gate_descriptor() = default; + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp new file mode 100644 index 0000000..c587000 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief TODO + * + */ + struct descriptor_tables + { + global_descriptor_table & gdt; ///< Reference to the global descriptor table. + interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. + }; + + auto initialize_descriptor_tables() -> descriptor_tables; + +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp new file mode 100644 index 0000000..c63932d --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP + +namespace teachos::arch::context_switching::descriptor_table +{ + struct interrupt_descriptor_table + { + }; + + auto initialize_interrupt_descriptor_table() -> void; + +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp new file mode 100644 index 0000000..e8935f4 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp @@ -0,0 +1,42 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" +#include "arch/stl/vector.hpp" + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + typedef stl::vector interrupt_descriptor_table; + + /** + * @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, interrupt_descriptor_table * 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. + interrupt_descriptor_table address = {}; ///< Non-owning pointer to the IDT base address. + }; + +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp new file mode 100644 index 0000000..724fbdf --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP + +#include "arch/context_switching/descriptor_table/global_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::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::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 new file mode 100644 index 0000000..51f5d9a --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/if.hpp @@ -0,0 +1,14 @@ +#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; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp new file mode 100644 index 0000000..666174c --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp @@ -0,0 +1,35 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP + +#include + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Far jump - A jump to an instruction located in a different segment. + */ + struct [[gnu::packed]] far_pointer + { + uint64_t offset; ///< Selector of the segment in which the jump occurs. + uint16_t segment; ///< Address to jump to within the segment. + }; + + /** + * @brief Near jump - A jump to an instruction within the current code segment. + * + * @param address to jump to. + */ + auto jmp(uint64_t address) -> void; + + /** + * @brief Far jump - A jump to an instruction located in a different segment than the current code segment but at the + * same privilege level. + * + * @param segment in which the jump occurs. + * @param offset to jump to. + */ + auto jmp(uint64_t segment, uint64_t offset) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 39bfe33..4fb23e5 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,7 +354,20 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +.global segment_register_reload_pointer +segment_register_reload_pointer: + xor %rax, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + + ret + _transition_to_long_mode: + call segment_register_reload_pointer + xor %rax, %rax mov %rax, %ss mov %rax, %ds diff --git a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp new file mode 100644 index 0000000..ee91e53 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp @@ -0,0 +1,5 @@ +#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp index dccce6b..639b079 100644 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -38,8 +38,8 @@ namespace teachos::arch::context_switching::descriptor_table std::bitset<20U> const limit{0xFFFFF}; access_byte const access_byte{access_level_bitset}; gdt_flags const gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor const code_segment{access_byte, gdt_flags, base, limit}; - return code_segment; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; } auto create_global_descriptor_table() -> global_descriptor_table @@ -53,6 +53,7 @@ namespace teachos::arch::context_switching::descriptor_table create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); segment_descriptor const user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); + // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); @@ -85,44 +86,7 @@ namespace teachos::arch::context_switching::descriptor_table gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - // Calculate the offset of the gdt in bytes to the TSS descriptor - uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); - kernel::cpu::load_task_register(tss_selector); - - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); return gdt; } - auto reload_cs_register(uint16_t gdt_data_offset) -> void - { - asm volatile("mov %[input], %%ax\n" - "mov %%ax %%ds\n" // Data Segment - "mov %%ax %%es\n" // Extra Segment (used for string operations) - "mov %%ax %%fs\n" // General-purpose Segment - "mov %%ax %%gs\n" // General-purpose Segment - "mov %%ax %%ss\n" // Stack Segment - : /* no output from call */ - : [input] "r"(gdt_data_offset) - : "ax"); - } - - auto reload_segment_register(uint16_t gdt_code_offset, uint16_t gdt_data_offset) -> void - { - /* - Whatever you do with the GDT has no effect on the CPU until you load new Segment Selectors into Segment Registers. - For most of these registers, the process is as simple as using MOV instructions, but changing the CS register - requires code resembling a jump or call to elsewhere, as this is the only way its value is meant to be changed. - */ - auto function = [gdt_data_offset] { reload_cs_register(gdt_data_offset); }; - - asm volatile("push %[input]\n" - "lea %[func], %%rax\n" - "push %%rax\n" - "retfq\n" - : /* no output from call */ - : [input] "r"(gdt_code_offset), [func] "r"(&function) - : "rax"); - } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp new file mode 100644 index 0000000..4d8b3e3 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp @@ -0,0 +1,38 @@ +#include "arch/context_switching/descriptor_table/initialization.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto initialize_descriptor_tables() -> descriptor_tables + { + decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + + // TODO: Replace random construction with return value of initialization. + interrupt_descriptor_table idt{}; + context_switching::descriptor_table::initialize_interrupt_descriptor_table(); + + kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + + uint16_t const tss_selector = (global_descriptor_table.size() - 1) << 3; + kernel::cpu::load_task_register(tss_selector); + + // Not sure if offset index or offset in bytes is needed! + // uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); + // kernel::cpu::load_task_register(tss_selector); + + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + + kernel::cpu::set_interrupt_flag(); + + descriptor_tables descriptor_tables = {global_descriptor_table, idt}; + return descriptor_tables; + } + +} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp new file mode 100644 index 0000000..9878664 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto initialize_interrupt_descriptor_table() -> void + { + // DO NOT + } + +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp new file mode 100644 index 0000000..b45324d --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, + interrupt_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } + +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp new file mode 100644 index 0000000..bbf34cb --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/idtr.cpp @@ -0,0 +1,19 @@ +#include "arch/kernel/cpu/idtr.hpp" + +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::interrupt_descriptor_table_pointer current_value{}; + asm("sidt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto load_interrupt_descriptor_table( + context_switching::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void + { + asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp new file mode 100644 index 0000000..2a25df5 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/if.cpp @@ -0,0 +1,5 @@ +namespace teachos::arch::kernel::cpu +{ + auto set_interrupt_flag() -> void { asm volatile("sti"); } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp new file mode 100644 index 0000000..009981b --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -0,0 +1,16 @@ +#include "arch/kernel/cpu/jmp.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto jmp(uint64_t address) -> void + { + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); + } + + auto jmp(uint64_t segment, uint64_t offset) -> void + { + far_pointer far_pointer = {offset, static_cast(segment)}; + asm volatile("jmp *%0" : : "m"(far_pointer)); + } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index da6d6d3..9433558 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,9 @@ #include "arch/kernel/main.hpp" -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/boot/pointers.hpp" +#include "arch/context_switching/descriptor_table/initialization.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,8 +63,7 @@ namespace teachos::arch::kernel heap_test(); - decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); - (void)global_descriptor_table.at(1); - video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); + decltype(auto) descriptor_tables = context_switching::descriptor_table::initialize_descriptor_tables(); + (void)descriptor_tables; } } // namespace teachos::arch::kernel -- cgit v1.2.3 From ccb47845d99e098c183f596cd1a3eb1db5c676da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 25 Mar 2025 12:04:43 +0000 Subject: Adjust file structure and fix compilation issues --- arch/x86_64/CMakeLists.txt | 18 ++-- .../descriptor_table/access_byte.hpp | 97 ---------------------- .../descriptor_table/gate_descriptor.hpp | 15 ---- .../descriptor_table/gdt_flags.hpp | 86 ------------------- .../descriptor_table/global_descriptor_table.hpp | 55 ------------ .../global_descriptor_table_pointer.hpp | 42 ---------- .../descriptor_table/initialization.hpp | 23 ----- .../interrupt_descriptor_table.hpp | 14 ---- .../interrupt_descriptor_table_pointer.hpp | 42 ---------- .../descriptor_table/segment_descriptor.hpp | 71 ---------------- .../descriptor_table/segment_descriptor_type.hpp | 27 ------ .../descriptor_table/task_state_segment.hpp | 32 ------- .../interrupt_descriptor_table/gate_descriptor.hpp | 15 ++++ .../interrupt_descriptor_table.hpp | 14 ++++ .../interrupt_descriptor_table_pointer.hpp | 42 ++++++++++ .../x86_64/include/arch/context_switching/main.hpp | 23 +++++ .../segment_descriptor_table/access_byte.hpp | 97 ++++++++++++++++++++++ .../segment_descriptor_table/gdt_flags.hpp | 86 +++++++++++++++++++ .../global_descriptor_table.hpp | 55 ++++++++++++ .../global_descriptor_table_pointer.hpp | 42 ++++++++++ .../segment_descriptor.hpp | 71 ++++++++++++++++ .../segment_descriptor_type.hpp | 27 ++++++ .../task_state_segment.hpp | 32 +++++++ arch/x86_64/include/arch/kernel/cpu/gdtr.hpp | 9 +- arch/x86_64/include/arch/kernel/cpu/idtr.hpp | 8 +- arch/x86_64/include/arch/kernel/cpu/tr.hpp | 2 - .../descriptor_table/access_byte.cpp | 15 ---- .../descriptor_table/gate_descriptor.cpp | 5 -- .../descriptor_table/gdt_flags.cpp | 18 ---- .../descriptor_table/global_descriptor_table.cpp | 92 -------------------- .../global_descriptor_table_pointer.cpp | 12 --- .../descriptor_table/initialization.cpp | 38 --------- .../interrupt_descriptor_table.cpp | 10 --- .../interrupt_descriptor_table_pointer.cpp | 13 --- .../descriptor_table/segment_descriptor.cpp | 35 -------- .../interrupt_descriptor_table/gate_descriptor.cpp | 5 ++ .../interrupt_descriptor_table.cpp | 10 +++ .../interrupt_descriptor_table_pointer.cpp | 13 +++ arch/x86_64/src/context_switching/main.cpp | 36 ++++++++ .../segment_descriptor_table/access_byte.cpp | 15 ++++ .../segment_descriptor_table/gdt_flags.cpp | 18 ++++ .../global_descriptor_table.cpp | 92 ++++++++++++++++++++ .../global_descriptor_table_pointer.cpp | 12 +++ .../segment_descriptor.cpp | 35 ++++++++ arch/x86_64/src/kernel/cpu/gdtr.cpp | 11 ++- arch/x86_64/src/kernel/cpu/idtr.cpp | 9 +- arch/x86_64/src/kernel/main.cpp | 4 +- 47 files changed, 768 insertions(+), 775 deletions(-) delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp delete mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp create mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp create mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp create mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/include/arch/context_switching/main.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/initialization.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/src/context_switching/main.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index a435ef9..cf92feb 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -92,15 +92,15 @@ target_sources("_exception" PRIVATE #]============================================================================] target_sources("_context" PRIVATE - "src/context_switching/descriptor_table/access_byte.cpp" - "src/context_switching/descriptor_table/gate_descriptor.cpp" - "src/context_switching/descriptor_table/gdt_flags.cpp" - "src/context_switching/descriptor_table/global_descriptor_table.cpp" - "src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp" - "src/context_switching/descriptor_table/initialization.cpp" - "src/context_switching/descriptor_table/interrupt_descriptor_table.cpp" - "src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp" - "src/context_switching/descriptor_table/segment_descriptor.cpp" + "src/context_switching/segment_descriptor_table/access_byte.cpp" + "src/context_switching/segment_descriptor_table/gdt_flags.cpp" + "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp" + "src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp" + "src/context_switching/segment_descriptor_table/segment_descriptor.cpp" + "src/context_switching/main.cpp" + "src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp" + "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp" + "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp deleted file mode 100644 index 646c2ca..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ /dev/null @@ -1,97 +0,0 @@ - -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP - -#include -#include - -namespace teachos::arch::context_switching::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 std::bitset 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). - ACCESS_LEVEL_KERNEL = - 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. - ACCESS_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. - ACCESS_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. - ACCESS_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 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<8U> 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==(access_byte const & other) const -> bool = default; - - private: - uint8_t _flags = {}; ///< Underlying bitset used to read the flags from. - }; -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp deleted file mode 100644 index f410219..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP - -namespace teachos::arch::context_switching::descriptor_table -{ - struct [[gnu::packed]] gate_descriptor - { - /** - * @brief Default Constructor. - */ - gate_descriptor() = default; - }; -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp deleted file mode 100644 index de41762..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP - -#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" - -#include - -namespace teachos::arch::context_switching::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 std::bitset and the meaning when they are set. - */ - enum bitset : uint8_t - { - LENGTH = 1U << 0U, ///< 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 bis - ///< is set the DEFAULT_LENGTH bis needs to be 0 - UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 - ///< GiB, 4 KiB otherwise. - STACK_POINTER_SIZE = 1U << 1U, ///< 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 << 1U, ///< Indicates the default length for code segments with effective addresses and - ///< operands. Enable for 32 bit, 16 bit otherwise. - GRANULARITY = 1U << 2U, ///< 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 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<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; - - private: - uint8_t _limit_2 : 4 = {}; - uint8_t _flags : 4 = {}; ///< Underlying bitset used to read the flags from. - }; -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp deleted file mode 100644 index 75e1e9d..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP - -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" -#include "arch/context_switching/descriptor_table/task_state_segment.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - enum class access_level - { - KERNEL, - USER - }; - - /** - * @brief Creates a generic segment_descriptor from the passed arguments. - * - * @param segment_descriptor_type Defines the type of the segment descriptor. - * @param access_level Defines the segment descriptor access level (KERNEL or USER). - * @return Created segment_descriptor. - */ - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) - -> segment_descriptor; - - /** - * @brief Creates a global_descriptor_table on the heap and fills it with the following segment registers: - * - * - Kernel Code Segment - * - Kernel Data Segment - * - User Code Segment - * - User Data Segment - * - * @return Copy of the created global_descriptor_table. - */ - auto create_global_descriptor_table() -> global_descriptor_table; - - /** - * @brief Creates a task_state_segment segment_descriptor on the heap. - * - * @param tss task_state_segment whose pointer is used in the segment_descriptor - * @return Created segment_descriptor. - */ - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor; - - /** - * @brief Initializes the global_descriptor_table and task_state_segment by loading them - * in the GDTR and TR registers respectively. - * - * @return Reference to the created global_descriptor_table. - */ - auto initialize_global_descriptor_table() -> global_descriptor_table &; - -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp deleted file mode 100644 index ed17be3..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP - -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" -#include "arch/stl/vector.hpp" - -#include - -namespace teachos::arch::context_switching::descriptor_table -{ - typedef stl::vector global_descriptor_table; - - /** - * @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, global_descriptor_table * 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. - global_descriptor_table * address = {}; ///< Non-owning pointer to the GDT base address. - }; -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp deleted file mode 100644 index c587000..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP - -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - /** - * @brief TODO - * - */ - struct descriptor_tables - { - global_descriptor_table & gdt; ///< Reference to the global descriptor table. - interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. - }; - - auto initialize_descriptor_tables() -> descriptor_tables; - -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp deleted file mode 100644 index c63932d..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP - -namespace teachos::arch::context_switching::descriptor_table -{ - struct interrupt_descriptor_table - { - }; - - auto initialize_interrupt_descriptor_table() -> void; - -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp deleted file mode 100644 index e8935f4..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP - -#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" -#include "arch/stl/vector.hpp" - -#include - -namespace teachos::arch::context_switching::descriptor_table -{ - typedef stl::vector interrupt_descriptor_table; - - /** - * @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, interrupt_descriptor_table * 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. - interrupt_descriptor_table address = {}; ///< Non-owning pointer to the IDT base address. - }; - -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp deleted file mode 100644 index 8714eb8..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP - -#include "arch/context_switching/descriptor_table/access_byte.hpp" -#include "arch/context_switching/descriptor_table/gdt_flags.hpp" -#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" - -namespace teachos::arch::context_switching::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 - { - /** - * @brief Default Constructor. - */ - segment_descriptor() = default; - - /** - * @brief Constructor. - * - * @note Created segment descriptor copies the given bytes into theese components ending with a 32 bit reserved - * field that has to be used, because the 64-bit segment descriptor needs to be big enough for two 32-bit segment - * descriptor. - * - 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(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(access_byte access_byte, gdt_flags flags, uint64_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 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 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) - uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) - }; -} // namespace teachos::arch::context_switching::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp deleted file mode 100644 index 4815fca..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP - -#include - -namespace teachos::arch::context_switching::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::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp deleted file mode 100644 index 1e306af..0000000 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP - -#include - -namespace teachos::arch::context_switching::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::descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP 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 new file mode 100644 index 0000000..2252b7b --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp @@ -0,0 +1,15 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + struct [[gnu::packed]] gate_descriptor + { + /** + * @brief Default Constructor. + */ + gate_descriptor() = default; + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP 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 new file mode 100644 index 0000000..ac52a39 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + struct interrupt_descriptor_table + { + }; + + auto initialize_interrupt_descriptor_table() -> void; + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_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 new file mode 100644 index 0000000..de40f90 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp @@ -0,0 +1,42 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" +#include "arch/stl/vector.hpp" + +#include + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + typedef stl::vector interrupt_descriptor_table; + + /** + * @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, interrupt_descriptor_table * 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. + interrupt_descriptor_table * address = {}; ///< Non-owning pointer to the IDT base address. + }; + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/include/arch/context_switching/main.hpp new file mode 100644 index 0000000..ef642d6 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/main.hpp @@ -0,0 +1,23 @@ +#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 TODO + * + */ + 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. + }; + + auto initialize_descriptor_tables() -> descriptor_tables; + +} // 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 new file mode 100644 index 0000000..bbf3f49 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/access_byte.hpp @@ -0,0 +1,97 @@ + +#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 std::bitset 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). + ACCESS_LEVEL_KERNEL = + 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. + ACCESS_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. + ACCESS_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. + ACCESS_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 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<8U> 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==(access_byte const & other) const -> bool = default; + + private: + uint8_t _flags = {}; ///< Underlying bitset 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 new file mode 100644 index 0000000..2ce5286 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp @@ -0,0 +1,86 @@ +#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 std::bitset and the meaning when they are set. + */ + enum bitset : uint8_t + { + LENGTH = 1U << 0U, ///< 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 bis + ///< is set the DEFAULT_LENGTH bis needs to be 0 + UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 + ///< GiB, 4 KiB otherwise. + STACK_POINTER_SIZE = 1U << 1U, ///< 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 << 1U, ///< Indicates the default length for code segments with effective addresses and + ///< operands. Enable for 32 bit, 16 bit otherwise. + GRANULARITY = 1U << 2U, ///< 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 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<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; + + private: + uint8_t _limit_2 : 4 = {}; + uint8_t _flags : 4 = {}; ///< Underlying bitset 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 new file mode 100644 index 0000000..a111a1f --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp @@ -0,0 +1,55 @@ +#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 +{ + enum class access_level + { + KERNEL, + USER + }; + + /** + * @brief Creates a generic segment_descriptor from the passed arguments. + * + * @param segment_descriptor_type Defines the type of the segment descriptor. + * @param access_level Defines the segment descriptor access level (KERNEL or USER). + * @return Created segment_descriptor. + */ + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) + -> segment_descriptor; + + /** + * @brief Creates a global_descriptor_table on the heap and fills it with the following segment registers: + * + * - Kernel Code Segment + * - Kernel Data Segment + * - User Code Segment + * - User Data Segment + * + * @return Copy of the created global_descriptor_table. + */ + auto create_global_descriptor_table() -> global_descriptor_table; + + /** + * @brief Creates a task_state_segment segment_descriptor on the heap. + * + * @param tss task_state_segment whose pointer is used in the segment_descriptor + * @return Created segment_descriptor. + */ + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor; + + /** + * @brief Initializes the global_descriptor_table and task_state_segment by loading them + * in the GDTR and TR registers respectively. + * + * @return Reference to the created global_descriptor_table. + */ + auto initialize_global_descriptor_table() -> global_descriptor_table &; + +} // 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 new file mode 100644 index 0000000..b66070b --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp @@ -0,0 +1,42 @@ +#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/context_switching/segment_descriptor_table/segment_descriptor.hpp" +#include "arch/stl/vector.hpp" + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + typedef stl::vector global_descriptor_table; + + /** + * @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, global_descriptor_table * 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. + global_descriptor_table * 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.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp new file mode 100644 index 0000000..7fe4ecb --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp @@ -0,0 +1,71 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_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 +{ + __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 + { + /** + * @brief Default Constructor. + */ + segment_descriptor() = default; + + /** + * @brief Constructor. + * + * @note Created segment descriptor copies the given bytes into theese components ending with a 32 bit reserved + * field that has to be used, because the 64-bit segment descriptor needs to be big enough for two 32-bit segment + * descriptor. + * - 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(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(access_byte access_byte, gdt_flags flags, uint64_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 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 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) + uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 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_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 new file mode 100644 index 0000000..8770b81 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief Possible overlying types of the segment descriptor. Allowing to discern between the major types, which + * result in different handling of the actual data contained in the descriptor. + */ + enum class segment_descriptor_type : uint8_t + { + SYSTEM_SEGMENT, ///< The segment is of type system, is distinguished by the Descriptor Type field in the Access + ///< Byte. Can be further distinguised to specific system segment types using the Type Field in the + ///< Access Byte. + DATA_SEGMENT, ///< The segment is of type data, is is distinguished by the Descriptor Type field in the Access + ///< Byte and the first bit of the Type Field in the Access Byte. Can be further distinguised to + ///< specific data segment types using the the remaining bits in the Type Field in the Access Byte. + CODE_SEGMENT, ///< The segment is of type code, is is distinguished by the Descriptor Type field in + ///< the Access Byte and the first bit of the Type Field in the Access Byte. Can be + ///< further distinguised to specific data segment types using the the remaining bits in + ///< the Type Field in the Access Byte. + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP diff --git a/arch/x86_64/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 new file mode 100644 index 0000000..d4aa5e8 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/task_state_segment.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP + +#include + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + /** + * @brief 64-bit task state segment + */ + struct [[gnu::packed]] task_state_segment + { + private: + uint32_t : 32; + uint64_t rsp0 = {}; + uint64_t rsp1 = {}; + uint64_t rsp2 = {}; + uint64_t : 64; + uint64_t ist1 = {}; + uint64_t ist2 = {}; + uint64_t ist3 = {}; + uint64_t ist4 = {}; + uint64_t ist5 = {}; + uint64_t ist6 = {}; + uint64_t ist7 = {}; + uint64_t : 64; + uint16_t : 16; + uint16_t io_map_base_address = {}; + }; +} // namespace teachos::arch::context_switching::segment_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_TASK_STATE_SEGMENT_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp index f9220b9..68b950d 100644 --- a/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP #define TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_HPP -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" #include #include @@ -14,14 +14,13 @@ namespace teachos::arch::kernel::cpu * * @return Value of GDTR register. */ - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer; + 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::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) - -> void; + auto load_global_descriptor_table( + context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void; } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp index 724fbdf..cb800d0 100644 --- a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp @@ -1,26 +1,26 @@ #ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP #define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.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::descriptor_table::interrupt_descriptor_table_pointer; + 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::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/include/arch/kernel/cpu/tr.hpp index 562fab7..7c856f1 100644 --- a/arch/x86_64/include/arch/kernel/cpu/tr.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/tr.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP #define TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP -#include "arch/context_switching/descriptor_table/task_state_segment.hpp" - #include #include diff --git a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp deleted file mode 100644 index 6b54451..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/context_switching/descriptor_table/access_byte.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - access_byte::access_byte(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto access_byte::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp deleted file mode 100644 index ee91e53..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp deleted file mode 100644 index 9e95182..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "arch/context_switching/descriptor_table/gdt_flags.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) - : _limit_2(limit.to_ulong() >> 16U) - , _flags(flags) - { - // Nothing to do. - } - - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool - { - return (std::bitset<4U>{_flags} & other) == other; - } - - auto descriptor_table::gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp deleted file mode 100644 index 639b079..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" - -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" -#include "arch/context_switching/descriptor_table/task_state_segment.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/gdtr.hpp" -#include "arch/kernel/cpu/tr.hpp" -#include "arch/stl/vector.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) - -> segment_descriptor - { - uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; - if (access_level == access_level::KERNEL) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; - } - else if (access_level == access_level::USER) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_USER; - } - - uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; - if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) - { - gdt_flags_bitset |= gdt_flags::LENGTH; - access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; - } - else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) - { - gdt_flags_bitset |= gdt_flags::UPPER_BOUND; - access_level_bitset |= access_byte::WRITABLE; - } - - uint64_t const base = 0x0; - std::bitset<20U> const limit{0xFFFFF}; - access_byte const access_byte{access_level_bitset}; - gdt_flags const gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; - return segment_descriptor; - } - - auto create_global_descriptor_table() -> global_descriptor_table - { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - - global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } - - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor - { - constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; - access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::TASK_STATE_SEGMENT_AVAILABLE}; - gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; - segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), TSS_LIMIT}; - return tss_descriptor; - } - - auto initialize_global_descriptor_table() -> global_descriptor_table & - { - // Global Descriptor Table needs to be kept alive - static auto gdt = create_global_descriptor_table(); - - global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; - kernel::cpu::load_global_descriptor_table(gdt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); - arch::exception_handling::assert( - gdt_pointer == stored_gdt_pointer, - "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - - return gdt; - } - -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp deleted file mode 100644 index f552496..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, - global_descriptor_table * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp deleted file mode 100644 index 4d8b3e3..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "arch/context_switching/descriptor_table/initialization.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - auto initialize_descriptor_tables() -> descriptor_tables - { - decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); - - // TODO: Replace random construction with return value of initialization. - interrupt_descriptor_table idt{}; - context_switching::descriptor_table::initialize_interrupt_descriptor_table(); - - kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); - - uint16_t const tss_selector = (global_descriptor_table.size() - 1) << 3; - kernel::cpu::load_task_register(tss_selector); - - // Not sure if offset index or offset in bytes is needed! - // uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); - // kernel::cpu::load_task_register(tss_selector); - - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - - kernel::cpu::set_interrupt_flag(); - - descriptor_tables descriptor_tables = {global_descriptor_table, idt}; - return descriptor_tables; - } - -} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp deleted file mode 100644 index 9878664..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - auto initialize_interrupt_descriptor_table() -> void - { - // DO NOT - } - -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp deleted file mode 100644 index b45324d..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - interrupt_descriptor_table * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } - -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp deleted file mode 100644 index 2385c58..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - segment_descriptor::segment_descriptor(uint128_t flags) - : _limit_1(flags << 112U) - , _base_1((flags >> 16U) << 88U) - , _access((flags >> 40U) << 80U) - , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) - , _base_2((flags >> 56U) << 32U) - { - // Nothing to do. - } - - segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, - std::bitset<20U> limit) - : _limit_1(limit.to_ulong()) - , _base_1(base) - , _access(access_byte) - , _flag(flags) - , _base_2(base >> 24U) - { - // Nothing to do - } - - auto segment_descriptor::get_segment_type() const -> segment_descriptor_type - { - if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) - { - return segment_descriptor_type::SYSTEM_SEGMENT; - } - return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; - } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp new file mode 100644 index 0000000..4f18197 --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -0,0 +1,5 @@ +#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp new file mode 100644 index 0000000..619a695 --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + auto initialize_interrupt_descriptor_table() -> void + { + // DO NOT + } + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp new file mode 100644 index 0000000..981944d --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, + interrupt_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp new file mode 100644 index 0000000..b682e79 --- /dev/null +++ b/arch/x86_64/src/context_switching/main.cpp @@ -0,0 +1,36 @@ +#include "arch/context_switching/main.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::context_switching +{ + auto initialize_descriptor_tables() -> descriptor_tables + { + decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); + + // TODO: Replace random construction with return value of initialization. + interrupt_descriptor_table::interrupt_descriptor_table idt{}; + interrupt_descriptor_table::initialize_interrupt_descriptor_table(); + + kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + + // Load task state segment descriptor from the last element in the global descriptor table, done by calculating + // offset in bytes to the start of the segment descriptor (5 * 16) = 80 + uint16_t const tss_selector = + (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + kernel::cpu::load_task_register(tss_selector); + + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + + kernel::cpu::set_interrupt_flag(); + + descriptor_tables tables = {global_descriptor_table, idt}; + return tables; + } +} // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp new file mode 100644 index 0000000..34a10f1 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp @@ -0,0 +1,15 @@ +#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + access_byte::access_byte(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto access_byte::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp new file mode 100644 index 0000000..9885bda --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp @@ -0,0 +1,18 @@ +#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) + : _limit_2(limit.to_ulong() >> 16U) + , _flags(flags) + { + // Nothing to do. + } + + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool + { + return (std::bitset<4U>{_flags} & other) == other; + } + + auto gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp new file mode 100644 index 0000000..1bbd24f --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -0,0 +1,92 @@ +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" + +#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/segment_descriptor_table/task_state_segment.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/gdtr.hpp" +#include "arch/kernel/cpu/tr.hpp" +#include "arch/stl/vector.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) + -> segment_descriptor + { + uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; + if (access_level == access_level::KERNEL) + { + access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; + } + else if (access_level == access_level::USER) + { + access_level_bitset |= access_byte::ACCESS_LEVEL_USER; + } + + uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::LENGTH; + access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::UPPER_BOUND; + access_level_bitset |= access_byte::WRITABLE; + } + + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + access_byte const access_byte{access_level_bitset}; + gdt_flags const gdt_flags{gdt_flags_bitset, limit}; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; + } + + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); + segment_descriptor const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); + + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); + + global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } + + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor + { + constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; + access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::TASK_STATE_SEGMENT_AVAILABLE}; + gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; + segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), TSS_LIMIT}; + return tss_descriptor; + } + + auto initialize_global_descriptor_table() -> global_descriptor_table & + { + // Global Descriptor Table needs to be kept alive + static auto gdt = create_global_descriptor_table(); + + global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; + kernel::cpu::load_global_descriptor_table(gdt_pointer); + + auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + arch::exception_handling::assert( + gdt_pointer == stored_gdt_pointer, + "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + + return gdt; + } + +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp new file mode 100644 index 0000000..132565f --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -0,0 +1,12 @@ +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, + global_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp new file mode 100644 index 0000000..6d831a1 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp @@ -0,0 +1,35 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor::segment_descriptor(uint128_t flags) + : _limit_1(flags << 112U) + , _base_1((flags >> 16U) << 88U) + , _access((flags >> 40U) << 80U) + , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) + , _base_2((flags >> 56U) << 32U) + { + // Nothing to do. + } + + segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, + std::bitset<20U> limit) + : _limit_1(limit.to_ulong()) + , _base_1(base) + , _access(access_byte) + , _flag(flags) + , _base_2(base >> 24U) + { + // Nothing to do + } + + auto segment_descriptor::get_segment_type() const -> segment_descriptor_type + { + if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) + { + return segment_descriptor_type::SYSTEM_SEGMENT; + } + return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/gdtr.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp index 2fe3a99..74a4e1c 100644 --- a/arch/x86_64/src/kernel/cpu/gdtr.cpp +++ b/arch/x86_64/src/kernel/cpu/gdtr.cpp @@ -1,19 +1,18 @@ #include "arch/kernel/cpu/gdtr.hpp" -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" namespace teachos::arch::kernel::cpu { - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer { - context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; + context_switching::segment_descriptor_table::global_descriptor_table_pointer current_value{}; asm("sgdt %[output]" : [output] "=m"(current_value)); return current_value; } - auto - load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) - -> void + auto load_global_descriptor_table( + context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void { asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); } diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp index bbf34cb..7aa20c1 100644 --- a/arch/x86_64/src/kernel/cpu/idtr.cpp +++ b/arch/x86_64/src/kernel/cpu/idtr.cpp @@ -1,18 +1,17 @@ #include "arch/kernel/cpu/idtr.hpp" -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" - namespace teachos::arch::kernel::cpu { - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + auto store_interrupt_descriptor_table() + -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer { - context_switching::descriptor_table::interrupt_descriptor_table_pointer current_value{}; + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer current_value{}; asm("sidt %[output]" : [output] "=m"(current_value)); return current_value; } auto load_interrupt_descriptor_table( - context_switching::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void { asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); } diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 9433558..7782d30 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,7 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/descriptor_table/initialization.hpp" +#include "arch/context_switching/main.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/jmp.hpp" #include "arch/memory/heap/bump_allocator.hpp" @@ -63,7 +63,7 @@ namespace teachos::arch::kernel heap_test(); - decltype(auto) descriptor_tables = context_switching::descriptor_table::initialize_descriptor_tables(); + decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); (void)descriptor_tables; } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 66fefaeb16bcbc4eae5ce5256ae76f51a155cded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 25 Mar 2025 16:58:24 +0000 Subject: Implement idtr structure and document possible flags. --- arch/x86_64/CMakeLists.txt | 7 +- .../interrupt_descriptor_table/gate_descriptor.hpp | 54 +++++++++++ .../interrupt_descriptor_table/idt_flags.hpp | 74 +++++++++++++++ .../interrupt_descriptor_table.hpp | 14 ++- .../interrupt_descriptor_table_pointer.hpp | 4 +- .../interrupt_descriptor_table/ist_offset.hpp | 41 ++++++++ .../segment_selector.hpp | 74 +++++++++++++++ .../x86_64/include/arch/context_switching/main.hpp | 3 +- .../segment_descriptor_table/access_byte.hpp | 14 +-- .../segment_descriptor_table/gdt_flags.hpp | 4 +- .../global_descriptor_table.hpp | 36 ------- .../global_descriptor_table_pointer.hpp | 2 +- arch/x86_64/include/arch/kernel/cpu/ss.hpp | 39 +------- .../arch/memory/allocator/physical_frame.hpp | 4 +- .../arch/memory/multiboot/elf_symbols_section.hpp | 2 +- .../include/arch/memory/multiboot/memory_map.hpp | 2 +- .../include/arch/memory/paging/virtual_page.hpp | 4 +- .../interrupt_descriptor_table/gate_descriptor.cpp | 19 ++++ .../interrupt_descriptor_table/idt_flags.cpp | 15 +++ .../interrupt_descriptor_table.cpp | 24 ++++- .../interrupt_descriptor_table/ist_offset.cpp | 10 ++ .../segment_selector.cpp | 16 ++++ arch/x86_64/src/context_switching/main.cpp | 7 +- .../global_descriptor_table.cpp | 105 ++++++++++----------- .../segment_descriptor.cpp | 10 +- arch/x86_64/src/kernel/cpu/ss.cpp | 29 ++---- 26 files changed, 425 insertions(+), 188 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp create mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp create mode 100644 arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index cf92feb..5242f3d 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -94,13 +94,16 @@ target_sources("_exception" PRIVATE target_sources("_context" PRIVATE "src/context_switching/segment_descriptor_table/access_byte.cpp" "src/context_switching/segment_descriptor_table/gdt_flags.cpp" - "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp" "src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp" + "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor.cpp" "src/context_switching/main.cpp" "src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp" - "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp" + "src/context_switching/interrupt_descriptor_table/idt_flags.cpp" "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp" + "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp" + "src/context_switching/interrupt_descriptor_table/ist_offset.cpp" + "src/context_switching/interrupt_descriptor_table/segment_selector.cpp" ) #[============================================================================[ 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 index 2252b7b..196430f 100644 --- 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 @@ -1,14 +1,68 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_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 IST + * - 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 = {}; ///< First part of the offset field (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 = {}; ///< Second part of the offset field (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 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 new file mode 100644 index 0000000..f153e36 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp @@ -0,0 +1,74 @@ + +#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 std::bitset and the meaning when they are set. + */ + enum bitset : uint8_t + { + INTERRUPT_GATE = 16U, ///< The actual type of gate segment is a interrupt gate. + TRAP_GATE = 17U, ///< 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 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<8U> 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==(idt_flags const & other) const -> bool = default; + + 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 index ac52a39..dd55cd7 100644 --- 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 @@ -1,13 +1,17 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_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 { - struct interrupt_descriptor_table - { - }; - - auto initialize_interrupt_descriptor_table() -> void; + /** + * @brief Initializes the interrupt_descriptor_table by loading it + * in the IDTR register. + * + * @return Reference to the created interrupt_descriptor_table. + */ + auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table &; } // namespace teachos::arch::context_switching::interrupt_descriptor_table 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 index de40f90..d853ff0 100644 --- 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 @@ -4,11 +4,9 @@ #include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" #include "arch/stl/vector.hpp" -#include - namespace teachos::arch::context_switching::interrupt_descriptor_table { - typedef stl::vector interrupt_descriptor_table; + using interrupt_descriptor_table = stl::vector; /** * @brief Represents a pointer to the Interrupt Descriptor Table (IDT). 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 new file mode 100644 index 0000000..f31a898 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp @@ -0,0 +1,41 @@ +#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 ist 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 index Index into local or global descriptor table. + */ + ist_offset(uint8_t index); + + /** + * @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. + }; +} // 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 new file mode 100644 index 0000000..c31e2d0 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp @@ -0,0 +1,74 @@ +#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 std::bitset 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. + * @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. + */ + segment_selector(uint16_t index, uint8_t flags); + + /** + * @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<3U> other) const -> bool; + + /** + * @brief Defaulted three-way comparsion operator. + */ + auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; + + 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. + }; +} // 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 index ef642d6..d2243ed 100644 --- a/arch/x86_64/include/arch/context_switching/main.hpp +++ b/arch/x86_64/include/arch/context_switching/main.hpp @@ -7,8 +7,7 @@ namespace teachos::arch::context_switching { /** - * @brief TODO - * + * @brief Contains the references to the tables required for context switching */ struct descriptor_tables { 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 index bbf3f49..3d7862c 100644 --- 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 @@ -43,17 +43,17 @@ namespace teachos::arch::context_switching::segment_descriptor_table 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). - ACCESS_LEVEL_KERNEL = + DESCRIPTOR_LEVEL_KERNEL = 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. - ACCESS_LEVEL_ADMIN = + 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. - ACCESS_LEVEL_PRIVILEGED_USER = + 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. - ACCESS_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. + 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. }; /** @@ -90,7 +90,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table auto operator==(access_byte const & other) const -> bool = default; private: - uint8_t _flags = {}; ///< Underlying bitset used to read the flags from. + uint8_t _flags = {}; ///< Underlying bits used to read the flags from. }; } // namespace teachos::arch::context_switching::segment_descriptor_table 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 index 2ce5286..fdf0044 100644 --- 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 @@ -78,8 +78,8 @@ namespace teachos::arch::context_switching::segment_descriptor_table auto operator==(gdt_flags const & other) const -> bool = default; private: - uint8_t _limit_2 : 4 = {}; - uint8_t _flags : 4 = {}; ///< Underlying bitset used to read the flags from. + 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 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 index a111a1f..f3067ba 100644 --- 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 @@ -6,42 +6,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - enum class access_level - { - KERNEL, - USER - }; - - /** - * @brief Creates a generic segment_descriptor from the passed arguments. - * - * @param segment_descriptor_type Defines the type of the segment descriptor. - * @param access_level Defines the segment descriptor access level (KERNEL or USER). - * @return Created segment_descriptor. - */ - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) - -> segment_descriptor; - - /** - * @brief Creates a global_descriptor_table on the heap and fills it with the following segment registers: - * - * - Kernel Code Segment - * - Kernel Data Segment - * - User Code Segment - * - User Data Segment - * - * @return Copy of the created global_descriptor_table. - */ - auto create_global_descriptor_table() -> global_descriptor_table; - - /** - * @brief Creates a task_state_segment segment_descriptor on the heap. - * - * @param tss task_state_segment whose pointer is used in the segment_descriptor - * @return Created segment_descriptor. - */ - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor; - /** * @brief Initializes the global_descriptor_table and task_state_segment by loading them * in the GDTR and TR registers respectively. 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 index b66070b..13d6f53 100644 --- 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 @@ -8,7 +8,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - typedef stl::vector global_descriptor_table; + using global_descriptor_table = stl::vector; /** * @brief Represents a pointer to the Global Descriptor Table (GDT). diff --git a/arch/x86_64/include/arch/kernel/cpu/ss.hpp b/arch/x86_64/include/arch/kernel/cpu/ss.hpp index 1fb6448..b5fa5e3 100644 --- a/arch/x86_64/include/arch/kernel/cpu/ss.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/ss.hpp @@ -1,55 +1,26 @@ #ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP #define TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + #include #include namespace teachos::arch::kernel::cpu { - /** - * @brief Represents a segment selector in the x86_64 architecture. - * - * 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 segment_selector - { - /** - * @brief Constructs a segment selector. - * - * @param index The index of the segment descriptor. - * @param table_indicator The table indicator (0 for GDT, 1 for LDT). - * @param requested_privilege_level The requested privilege level (0-3). - */ - segment_selector(uint16_t index, std::bitset<1U> table_indicator, std::bitset<2U> requested_privilege_level); - - /** - * @brief Converts the segment selector to a 16-bit value. - * - * @return uint16_t The 16-bit representation of the segment selector. - */ - auto to_uint16() const -> uint16_t; - - private: - uint16_t index; - std::bitset<1U> table_indicator; - std::bitset<2U> requested_privilege_level; - }; - /** * @brief Reads the current value of the stack segment (SS) register. * - * @return uint16_t The current SS register value. + * @return The current SS register value. */ - auto read_ss() -> uint16_t; + auto read_ss() -> context_switching::interrupt_descriptor_table::segment_selector; /** * @brief Writes a new value to the stack segment (SS) register. * * @param selector The segment selector to be written to SS. */ - auto write_ss(segment_selector selector) -> void; + auto write_ss(context_switching::interrupt_descriptor_table::segment_selector selector) -> void; } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 7ea5517..cb6c5b3 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::allocator { - typedef std::size_t physical_address; + using physical_address = std::size_t; std::size_t constexpr PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. @@ -79,7 +79,7 @@ namespace teachos::arch::memory::allocator {}; ///< Index number of the current physical frame, used to distinguish it from other frames. }; - typedef stl::container> frame_container; + using frame_container = stl::container>; } // namespace teachos::arch::memory::allocator 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 4c7470b..730bcaf 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 @@ -162,7 +162,7 @@ namespace teachos::arch::memory::multiboot ///< contained in the section, to ensure byte alignment is actually 4 byte. }; - typedef stl::container> elf_section_header_container; + using elf_section_header_container = stl::container>; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index cc8db8c..68394c8 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -46,7 +46,7 @@ namespace teachos::arch::memory::multiboot struct memory_area entries; ///< Specific memory regions. }; - typedef stl::container> memory_area_container; + using memory_area_container = stl::container>; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index d9164a0..a6c8c39 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging { - typedef std::size_t virtual_address; + using virtual_address = std::size_t; /** * @brief Virtual page entry contained in P1 page tables @@ -84,7 +84,7 @@ namespace teachos::arch::memory::paging {}; ///< Index number of the current virtual page, used to distinguish it from other pages. }; - typedef stl::container> page_container; + using page_container = stl::container>; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp index 4f18197..28f289c 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -2,4 +2,23 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { + gate_descriptor::gate_descriptor(uint128_t flags) + : _offset_1(flags) + , _selector(flags >> 19U, flags >> 16U) + , _ist(flags >> 32U) + , _flags(flags >> 40U) + , _offset_2(flags >> 48U) + { + // Nothing to do. + } + + gate_descriptor::gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset) + : _offset_1(offset) + , _selector(selector) + , _ist(ist) + , _flags(flags) + , _offset_2(offset >> 16U) + { + // Nothing to do. + } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp new file mode 100644 index 0000000..e7379ef --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp @@ -0,0 +1,15 @@ +#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + idt_flags::idt_flags(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto idt_flags::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 619a695..7346248 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -1,10 +1,28 @@ #include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/idtr.hpp" + namespace teachos::arch::context_switching::interrupt_descriptor_table { - auto initialize_interrupt_descriptor_table() -> void + namespace { - // DO NOT - } + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { return interrupt_descriptor_table{}; } + } // namespace + + auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table & + { + // Interrupt Descriptor Table needs to be kept alive + static auto idt = create_interrupt_descriptor_table(); + interrupt_descriptor_table_pointer idt_pointer{static_cast(idt.size() - 1), &idt}; + kernel::cpu::load_interrupt_descriptor_table(idt_pointer); + + auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); + arch::exception_handling::assert( + idt_pointer == stored_gdt_pointer, + "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); + + return idt; + } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp new file mode 100644 index 0000000..a70e75d --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + ist_offset::ist_offset(uint8_t index) + : _ist(index) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp new file mode 100644 index 0000000..494e50f --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -0,0 +1,16 @@ +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + segment_selector::segment_selector(uint16_t index, uint8_t flags) + : _flags(flags) + , _index(index) + { + // Nothing to do. + } + + auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool + { + return (std::bitset<3U>{_flags} & other) == other; + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index b682e79..95a25e0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -11,10 +11,7 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); - - // TODO: Replace random construction with return value of initialization. - interrupt_descriptor_table::interrupt_descriptor_table idt{}; - interrupt_descriptor_table::initialize_interrupt_descriptor_table(); + decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); @@ -30,7 +27,7 @@ namespace teachos::arch::context_switching kernel::cpu::set_interrupt_flag(); - descriptor_tables tables = {global_descriptor_table, idt}; + descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; return tables; } } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index 1bbd24f..69cce19 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -9,69 +9,66 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) - -> segment_descriptor + namespace { - uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; - if (access_level == access_level::KERNEL) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; - } - else if (access_level == access_level::USER) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_USER; - } - uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; - if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level) + -> segment_descriptor { - gdt_flags_bitset |= gdt_flags::LENGTH; - access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; + uint8_t access_level_bits = + access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT | *reinterpret_cast(&access_level); + uint8_t gdt_flags_bits = gdt_flags::GRANULARITY; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + gdt_flags_bits |= gdt_flags::LENGTH; + access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + gdt_flags_bits |= gdt_flags::UPPER_BOUND; + access_level_bits |= access_byte::WRITABLE; + } + + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + access_byte const access_byte{access_level_bits}; + gdt_flags const gdt_flags{gdt_flags_bits, limit}; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; } - else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor { - gdt_flags_bitset |= gdt_flags::UPPER_BOUND; - access_level_bitset |= access_byte::WRITABLE; + constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; + access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL | + access_byte::TASK_STATE_SEGMENT_AVAILABLE}; + gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; + segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), + TSS_LIMIT}; + return tss_descriptor; } - uint64_t const base = 0x0; - std::bitset<20U> const limit{0xFFFFF}; - access_byte const access_byte{access_level_bitset}; - gdt_flags const gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; - return segment_descriptor; - } - - auto create_global_descriptor_table() -> global_descriptor_table - { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor - { - constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; - access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::TASK_STATE_SEGMENT_AVAILABLE}; - gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; - segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), TSS_LIMIT}; - return tss_descriptor; - } + global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } + } // namespace auto initialize_global_descriptor_table() -> global_descriptor_table & { diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp index 6d831a1..74f93b2 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp @@ -3,11 +3,11 @@ namespace teachos::arch::context_switching::segment_descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) - : _limit_1(flags << 112U) - , _base_1((flags >> 16U) << 88U) - , _access((flags >> 40U) << 80U) - , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) - , _base_2((flags >> 56U) << 32U) + : _limit_1(flags) + , _base_1(flags >> 16U) + , _access(flags >> 40U) + , _flag(flags >> 52U, flags >> 48U) + , _base_2(flags >> 56U) { // Nothing to do. } diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp index 1f28e7f..0978eca 100644 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -2,32 +2,15 @@ namespace teachos::arch::kernel::cpu { - segment_selector::segment_selector(uint16_t index, std::bitset<1U> table_indicator, - std::bitset<2U> requested_privilege_level) - : index(index) - , table_indicator(table_indicator) - , requested_privilege_level(requested_privilege_level) + auto read_ss() -> context_switching::interrupt_descriptor_table::segment_selector { - // Nothing to do - } - - auto segment_selector::to_uint16() const -> uint16_t - { - return static_cast((index << 3) | (table_indicator.to_ulong() << 2) | - requested_privilege_level.to_ulong()); - } - - auto read_ss() -> uint16_t - { - uint16_t segment_selector; - asm volatile("mov %%ss, %[output]" : [output] "=r"(segment_selector)); + context_switching::interrupt_descriptor_table::segment_selector segment_selector{}; + asm volatile("mov %%ss, %[output]" : [output] "=m"(segment_selector)); return segment_selector; } - auto write_ss(segment_selector selector) -> void + auto write_ss(context_switching::interrupt_descriptor_table::segment_selector selector) -> void { - uint16_t ss = selector.to_uint16(); - asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "r"(ss)); + asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "m"(selector)); } - -} // namespace teachos::arch::kernel::cpu \ No newline at end of file +} // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 96711d45ad7fb5b96cfd2b4fffda8756fe68fcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 26 Mar 2025 09:33:44 +0000 Subject: Fixing pointer values and adding basic idt value --- .../interrupt_descriptor_table/gate_descriptor.hpp | 6 ++++-- .../interrupt_descriptor_table.cpp | 20 ++++++++++++++++++-- .../global_descriptor_table.cpp | 5 ++++- 3 files changed, 26 insertions(+), 5 deletions(-) (limited to 'arch') 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 index 196430f..a652e0c 100644 --- 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 @@ -57,11 +57,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table private: // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _offset_1 = {}; ///< First part of the offset field (0 - 15) + uint16_t _offset_1 = {}; ///< First part of the offset field. Represents the address of the entry point of the + ///< Interrupt Service Routine. (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 = {}; ///< Second part of the offset field (48 - 95) + uint64_t _offset_2 : 48 = {}; ///< Second part of the offset field. Represents the address of the entry point of + ///< the Interrupt Service Routine. (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 diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 7346248..8bcce65 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -7,7 +7,22 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { namespace { - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { return interrupt_descriptor_table{}; } + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table + { + // TODO: Fix offset and ist and selector index + uint64_t const offset = 0x0; + segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset const ist{0U}; + idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE}; + gate_descriptor const interrupt_gate{selector, ist, flags, offset}; + + segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset const ist{0U}; + idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; + gate_descriptor const trap_gate{selector, ist, flags, offset}; + + return interrupt_descriptor_table{interrupt_gate, trap_gate}; + } } // namespace auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table & @@ -15,7 +30,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table // Interrupt Descriptor Table needs to be kept alive static auto idt = create_interrupt_descriptor_table(); - interrupt_descriptor_table_pointer idt_pointer{static_cast(idt.size() - 1), &idt}; + interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), + &idt}; kernel::cpu::load_interrupt_descriptor_table(idt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index 69cce19..e6a489c 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -75,7 +75,10 @@ namespace teachos::arch::context_switching::segment_descriptor_table // Global Descriptor Table needs to be kept alive static auto gdt = create_global_descriptor_table(); - global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; + // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, + // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. + global_descriptor_table_pointer gdt_pointer{static_cast((gdt.size() * sizeof(segment_descriptor)) - 1), + &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); -- cgit v1.2.3 From db555089dea369d9dd3010d1853077e7a4118b90 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 26 Mar 2025 10:08:40 +0000 Subject: add llm suggestion to idt creation --- .../interrupt_descriptor_table.cpp | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 8bcce65..0555e4c 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -9,19 +9,22 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // TODO: Fix offset and ist and selector index - uint64_t const offset = 0x0; - segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset const ist{0U}; - idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE}; - gate_descriptor const interrupt_gate{selector, ist, flags, offset}; - - segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset const ist{0U}; - idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; - gate_descriptor const trap_gate{selector, ist, flags, offset}; - - return interrupt_descriptor_table{interrupt_gate, trap_gate}; + interrupt_descriptor_table idt{}; + + // Define basic exception handlers (at least for CPU exceptions 0x00-0x1F) + for (uint8_t vector = 0; vector < 32; ++vector) + { + uint64_t offset = reinterpret_cast(default_exception_handler); // Use a real handler function + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; // Default stack offset (can be updated for IST) + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; + + idt.push_back(gate_descriptor{selector, ist, flags, offset}); + } + + // Additional entries for hardware interrupts (IRQs) and syscalls can be added here + + return idt; } } // namespace -- cgit v1.2.3 From a6c5f6a273d0c5c4161f600fca6d4fe49858c23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 27 Mar 2025 09:40:32 +0000 Subject: Attempt to fix crash in far jump. WIP does not return from call to assembler method --- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- .../segment_selector.hpp | 9 ++++++--- arch/x86_64/include/arch/kernel/cpu/if.hpp | 7 +++++++ arch/x86_64/include/arch/kernel/cpu/jmp.hpp | 14 ++++++++------ arch/x86_64/src/boot/boot.s | 2 +- .../interrupt_descriptor_table.cpp | 22 ++++++---------------- arch/x86_64/src/context_switching/main.cpp | 5 ++++- arch/x86_64/src/kernel/cpu/if.cpp | 2 ++ arch/x86_64/src/kernel/cpu/jmp.cpp | 6 ++---- 9 files changed, 37 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 2a43f22..5bcb792 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -11,7 +11,7 @@ namespace teachos::arch::boot extern "C" size_t const multiboot_information_pointer; /** - * @brief Address pointing to the start of the multiboot information structure. + * @brief Address pointing to the method that clears all segment registers. */ extern "C" size_t const segment_register_reload_pointer; 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 index c31e2d0..73cd176 100644 --- 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 @@ -43,7 +43,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table /** * @brief Constructor. * - * @param index Index into the local or global descriptor table. + * @param index 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. * @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. */ @@ -66,8 +67,10 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; 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. + 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 diff --git a/arch/x86_64/include/arch/kernel/cpu/if.hpp b/arch/x86_64/include/arch/kernel/cpu/if.hpp index 51f5d9a..48707dc 100644 --- a/arch/x86_64/include/arch/kernel/cpu/if.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/if.hpp @@ -9,6 +9,13 @@ namespace teachos::arch::kernel::cpu */ 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/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp index 666174c..5bc7d07 100644 --- a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp @@ -1,6 +1,8 @@ #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 @@ -10,14 +12,15 @@ namespace teachos::arch::kernel::cpu */ struct [[gnu::packed]] far_pointer { - uint64_t offset; ///< Selector of the segment in which the jump occurs. - uint16_t segment; ///< Address to jump to within the segment. + uint64_t offset; ///< Selector of the segment in which the jump occurs. (0- 63) + context_switching::interrupt_descriptor_table::segment_selector + selector; ///< Address to jump to within the segment. (64 - 79) }; /** * @brief Near jump - A jump to an instruction within the current code segment. * - * @param address to jump to. + * @param address Address we want to jump to. */ auto jmp(uint64_t address) -> void; @@ -25,10 +28,9 @@ namespace teachos::arch::kernel::cpu * @brief Far jump - A jump to an instruction located in a different segment than the current code segment but at the * same privilege level. * - * @param segment in which the jump occurs. - * @param offset to jump to. + * @param pointer 64-bit operand size far pointer that we should jump too. */ - auto jmp(uint64_t segment, uint64_t offset) -> void; + auto jmp(far_pointer pointer) -> void; } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 4fb23e5..35a6121 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -366,7 +366,7 @@ segment_register_reload_pointer: ret _transition_to_long_mode: - call segment_register_reload_pointer + //call segment_register_reload_pointer xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 0555e4c..ddc098e 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -9,22 +9,12 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - interrupt_descriptor_table idt{}; - - // Define basic exception handlers (at least for CPU exceptions 0x00-0x1F) - for (uint8_t vector = 0; vector < 32; ++vector) - { - uint64_t offset = reinterpret_cast(default_exception_handler); // Use a real handler function - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; // Default stack offset (can be updated for IST) - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; - - idt.push_back(gate_descriptor{selector, ist, flags, offset}); - } - - // Additional entries for hardware interrupts (IRQs) and syscalls can be added here - - return idt; + uint64_t offset = 0U; + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL}; + gate_descriptor gate_descriptor{selector, ist, flags, offset}; + return interrupt_descriptor_table{gate_descriptor}; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 95a25e0..c3c0cf0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,7 +13,10 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + interrupt_descriptor_table::segment_selector segment_selector{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::jmp(pointer); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating // offset in bytes to the start of the segment descriptor (5 * 16) = 80 diff --git a/arch/x86_64/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp index 2a25df5..60a90a3 100644 --- a/arch/x86_64/src/kernel/cpu/if.cpp +++ b/arch/x86_64/src/kernel/cpu/if.cpp @@ -2,4 +2,6 @@ namespace teachos::arch::kernel::cpu { auto set_interrupt_flag() -> void { asm volatile("sti"); } + auto clear_interrupt_flag() -> void { asm volatile("cli"); } + } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 009981b..205c4a9 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -7,10 +7,8 @@ namespace teachos::arch::kernel::cpu asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } - auto jmp(uint64_t segment, uint64_t offset) -> void + auto jmp(far_pointer pointer) -> void { - far_pointer far_pointer = {offset, static_cast(segment)}; - asm volatile("jmp *%0" : : "m"(far_pointer)); + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); } - } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 9ddfcd02413a93718e8cde53f9ba5a96a5b29b8f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Mar 2025 14:02:05 +0000 Subject: update long jump handling --- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- arch/x86_64/src/boot/boot.s | 16 ++++++---------- arch/x86_64/src/context_switching/main.cpp | 6 ++---- arch/x86_64/src/kernel/cpu/jmp.cpp | 10 ++++++---- 4 files changed, 15 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 5bcb792..5092fa6 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -13,7 +13,7 @@ namespace teachos::arch::boot /** * @brief Address pointing to the method that clears all segment registers. */ - extern "C" size_t const segment_register_reload_pointer; + extern "C" auto reload_segment_register_trampoline() -> void; } // namespace teachos::arch::boot diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 35a6121..f6c7978 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,8 +354,11 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global segment_register_reload_pointer -segment_register_reload_pointer: +.global reload_segment_register_trampoline +reload_segment_register_trampoline: + jmp 0x08, $_reload_cs + +_reload_cs: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -366,14 +369,7 @@ segment_register_reload_pointer: ret _transition_to_long_mode: - //call segment_register_reload_pointer - - xor %rax, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs + call _reload_cs movl $0xb8000, (vga_buffer_pointer) diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c3c0cf0..1417a25 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,10 +13,8 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; - kernel::cpu::jmp(pointer); + // Execute trampoline function for the GDT loading long jump + boot::reload_segment_register_trampoline(); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating // offset in bytes to the start of the segment descriptor (5 * 16) = 80 diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 205c4a9..78b65f4 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -7,8 +7,10 @@ namespace teachos::arch::kernel::cpu asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } - auto jmp(far_pointer pointer) -> void - { - asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } + // auto jmp(far_pointer pointer) -> void + // { + // asm volatile("ljmp $[segment_selector],$[address]" + // : /* no output from call */ + // : [segment_selector] "m"(pointer.selector), [address] "m"(pointer.offset)); + // } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From e0eae9b9e905a1842b333823bfdb7c253cda8d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 28 Mar 2025 09:59:09 +0000 Subject: Revert "update long jump handling" This reverts commit 9ddfcd02413a93718e8cde53f9ba5a96a5b29b8f. --- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- arch/x86_64/src/boot/boot.s | 16 ++++++++++------ arch/x86_64/src/context_switching/main.cpp | 6 ++++-- arch/x86_64/src/kernel/cpu/jmp.cpp | 10 ++++------ 4 files changed, 19 insertions(+), 15 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 5092fa6..5bcb792 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -13,7 +13,7 @@ namespace teachos::arch::boot /** * @brief Address pointing to the method that clears all segment registers. */ - extern "C" auto reload_segment_register_trampoline() -> void; + extern "C" size_t const segment_register_reload_pointer; } // namespace teachos::arch::boot diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index f6c7978..35a6121 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,11 +354,8 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global reload_segment_register_trampoline -reload_segment_register_trampoline: - jmp 0x08, $_reload_cs - -_reload_cs: +.global segment_register_reload_pointer +segment_register_reload_pointer: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -369,7 +366,14 @@ _reload_cs: ret _transition_to_long_mode: - call _reload_cs + //call segment_register_reload_pointer + + xor %rax, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs movl $0xb8000, (vga_buffer_pointer) diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 1417a25..c3c0cf0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,8 +13,10 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - // Execute trampoline function for the GDT loading long jump - boot::reload_segment_register_trampoline(); + interrupt_descriptor_table::segment_selector segment_selector{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::jmp(pointer); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating // offset in bytes to the start of the segment descriptor (5 * 16) = 80 diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 78b65f4..205c4a9 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -7,10 +7,8 @@ namespace teachos::arch::kernel::cpu asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } - // auto jmp(far_pointer pointer) -> void - // { - // asm volatile("ljmp $[segment_selector],$[address]" - // : /* no output from call */ - // : [segment_selector] "m"(pointer.selector), [address] "m"(pointer.offset)); - // } + auto jmp(far_pointer pointer) -> void + { + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); + } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 437c3554f9a86b6347d97f5e2a82543c1e068b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 28 Mar 2025 10:52:25 +0000 Subject: Attempt to fix ljmp. Might not be possible in Long mode --- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- arch/x86_64/include/arch/kernel/cpu/jmp.hpp | 6 +++--- arch/x86_64/src/boot/boot.s | 6 +++--- arch/x86_64/src/context_switching/main.cpp | 2 +- arch/x86_64/src/kernel/cpu/jmp.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 5bcb792..c08de52 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -13,7 +13,7 @@ namespace teachos::arch::boot /** * @brief Address pointing to the method that clears all segment registers. */ - extern "C" size_t const segment_register_reload_pointer; + extern "C" size_t reload_segment_register; } // namespace teachos::arch::boot diff --git a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp index 5bc7d07..163fac6 100644 --- a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp @@ -12,9 +12,9 @@ namespace teachos::arch::kernel::cpu */ struct [[gnu::packed]] far_pointer { - uint64_t offset; ///< Selector of the segment in which the jump occurs. (0- 63) + std::size_t function; ///< Address of the function we want to jump too. (0- 63) context_switching::interrupt_descriptor_table::segment_selector - selector; ///< Address to jump to within the segment. (64 - 79) + selector; ///< Segment selector that shows the segment we want to jump into. (64 - 79) }; /** @@ -22,7 +22,7 @@ namespace teachos::arch::kernel::cpu * * @param address Address we want to jump to. */ - auto jmp(uint64_t address) -> void; + auto jmp(std::size_t address) -> void; /** * @brief Far jump - A jump to an instruction located in a different segment than the current code segment but at the diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 35a6121..bf150a3 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,8 +354,8 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global segment_register_reload_pointer -segment_register_reload_pointer: +.global reload_segment_register +reload_segment_register: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -366,7 +366,7 @@ segment_register_reload_pointer: ret _transition_to_long_mode: - //call segment_register_reload_pointer + //call reload_segment_register xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c3c0cf0..5d19f23 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -15,7 +15,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::far_pointer pointer{boot::reload_segment_register, segment_selector}; kernel::cpu::jmp(pointer); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 205c4a9..0c94693 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -2,13 +2,13 @@ namespace teachos::arch::kernel::cpu { - auto jmp(uint64_t address) -> void + auto jmp(std::size_t address) -> void { asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } auto jmp(far_pointer pointer) -> void { - asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); + asm volatile("rex64 ljmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From fbd1ebe4f7c5985554fdca7c7fc05de15d47dd3a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Mar 2025 18:35:28 +0100 Subject: gdt: fix reload of GDT The core problems were/are the following: - The flags of the segments were not entirely correct. Please recheck them against the spec! - The GDT pointer did not contain the address of the first (null) GTD entry, but the address of the stl::vector containing the GDT entries. - The far pointer must consist of: - the address to jump to - the byte index into the GDT for the desired segement descriptor to be loaded into CS. - The type of the "dummy" function we jump to was wrong (it's a function, we should declare it as such). - We cannot enable interrupts right now, since we die with a triple fault. This is caused by some initia fault which seems to lead to a general protection fault, which then triple faults since we cannot find the IDT. Some FIXMEs have been added to the code. Please look at them carefully and compare things against the specs. --- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- .../segment_descriptor_table/gdt_flags.hpp | 17 ++++++++++----- .../global_descriptor_table_pointer.hpp | 4 ++-- arch/x86_64/include/arch/kernel/cpu/jmp.hpp | 7 +++--- arch/x86_64/src/boot/boot.s | 3 +++ arch/x86_64/src/context_switching/main.cpp | 25 +++++++++++----------- .../global_descriptor_table.cpp | 8 ++++--- .../global_descriptor_table_pointer.cpp | 2 +- 8 files changed, 39 insertions(+), 29 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index c08de52..9bf5cfd 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -13,7 +13,7 @@ namespace teachos::arch::boot /** * @brief Address pointing to the method that clears all segment registers. */ - extern "C" size_t reload_segment_register; + extern "C" void reload_segment_register(); } // namespace teachos::arch::boot 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 index fdf0044..764aec5 100644 --- 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 @@ -18,17 +18,24 @@ namespace teachos::arch::context_switching::segment_descriptor_table */ enum bitset : uint8_t { - LENGTH = 1U << 0U, ///< 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 bis - ///< is set the DEFAULT_LENGTH bis needs to be 0 + 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 bis + ///< is set the DEFAULT_LENGTH bis needs to be 0 + + // FIXME: Where does this come from, and is this value correct? UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 ///< GiB, 4 KiB otherwise. + + // FIXME: Where does this come from, and is this value correct? STACK_POINTER_SIZE = 1U << 1U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. + + // FIXME: Where does this come from, and is this value correct? DEFAULT_LENGTH = 1U << 1U, ///< Indicates the default length for code segments with effective addresses and ///< operands. Enable for 32 bit, 16 bit otherwise. - GRANULARITY = 1U << 2U, ///< Indicates the size the Limit value in the segment descriptor is scaled by 1 Byte + + 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. }; 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 index 13d6f53..6fac2a0 100644 --- 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 @@ -26,7 +26,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Constructor. */ - global_descriptor_table_pointer(uint16_t table_length, global_descriptor_table * address); + global_descriptor_table_pointer(uint16_t table_length, segment_descriptor * address); /** * @brief Defaulted three-way comparsion operator. @@ -35,7 +35,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table private: uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - global_descriptor_table * address = {}; ///< Non-owning pointer to the GDT base address. + segment_descriptor * address = {}; ///< Non-owning pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp index 163fac6..0ed38e9 100644 --- a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp @@ -10,11 +10,10 @@ namespace teachos::arch::kernel::cpu /** * @brief Far jump - A jump to an instruction located in a different segment. */ - struct [[gnu::packed]] far_pointer + struct far_pointer { - std::size_t function; ///< Address of the function we want to jump too. (0- 63) - context_switching::interrupt_descriptor_table::segment_selector - selector; ///< Segment selector that shows the segment we want to jump into. (64 - 79) + void (*function)(); ///< Address of the function we want to jump too. (0-63) + std::uint16_t index; ///< Index of the GDT entry we want to load into register CS. (64-79) }; /** diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index bf150a3..108dbe5 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -356,6 +356,9 @@ prepare_page_maps: .global reload_segment_register reload_segment_register: + // FIXME: maybe we should set the actually correct values here. We'd need to communicate them down from C++. + // Alternatively, we could probably implement this as a [[gnu::naked]] function in C++, to have easier access to + // arguments and symbols. Maybe later. xor %rax, %rax mov %rax, %ss mov %rax, %ds diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5d19f23..a5bd3fb 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,22 +13,21 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::reload_segment_register, segment_selector}; - kernel::cpu::jmp(pointer); + kernel::cpu::far_pointer pointer{&boot::reload_segment_register, 1 * sizeof(segment_descriptor_table::segment_descriptor)}; + asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m" (pointer)); - // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // offset in bytes to the start of the segment descriptor (5 * 16) = 80 - uint16_t const tss_selector = - (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); - kernel::cpu::load_task_register(tss_selector); + // // Load task state segment descriptor from the last element in the global descriptor table, done by calculating + // // offset in bytes to the start of the segment descriptor (5 * 16) = 80 + // uint16_t const tss_selector = + // (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + // kernel::cpu::load_task_register(tss_selector); - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + // auto const stored_task_register = kernel::cpu::store_task_register(); + // arch::exception_handling::assert(tss_selector == stored_task_register, + // "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - kernel::cpu::set_interrupt_flag(); + // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP. Maybe because no IDT is loaded? Maybe our boot code segment is not set up correctly? + // kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; return tables; diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index e6a489c..37ee778 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -20,12 +20,14 @@ namespace teachos::arch::context_switching::segment_descriptor_table uint8_t gdt_flags_bits = gdt_flags::GRANULARITY; if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) { - gdt_flags_bits |= gdt_flags::LENGTH; + gdt_flags_bits |= gdt_flags::LONG_MODE; access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - gdt_flags_bits |= gdt_flags::UPPER_BOUND; + gdt_flags_bits |= 1 << 2; + // FIXME: Look at those bit flags, something seems off. + // gdt_flags_bits |= gdt_flags::UPPER_BOUND; access_level_bits |= access_byte::WRITABLE; } @@ -78,7 +80,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. global_descriptor_table_pointer gdt_pointer{static_cast((gdt.size() * sizeof(segment_descriptor)) - 1), - &gdt}; + gdt.data()}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp index 132565f..a4a5de8 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -3,7 +3,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, - global_descriptor_table * address) + segment_descriptor * address) : table_length(table_length) , address(address) { -- cgit v1.2.3 From aba154ad01fc0e1e1274f2582b1493e78daa2559 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 29 Mar 2025 14:47:04 +0000 Subject: fix gdt segments, improve idt and trial&error for triple fault --- arch/x86_64/CMakeLists.txt | 8 ++++++ .../interrupt_descriptor_table/gate_descriptor.hpp | 13 +++++----- .../interrupt_descriptor_table.hpp | 6 ++--- .../interrupt_descriptor_table_pointer.hpp | 12 ++++----- .../segment_descriptor_table/gdt_flags.hpp | 22 ++++++---------- .../generic_interrupt_handler.hpp | 28 ++++++++++++++++++++ arch/x86_64/src/boot/boot.s | 11 +------- .../interrupt_descriptor_table/gate_descriptor.cpp | 2 ++ .../interrupt_descriptor_table.cpp | 14 ++++++---- .../interrupt_descriptor_table_pointer.cpp | 2 +- arch/x86_64/src/context_switching/main.cpp | 30 +++++++++++++--------- .../global_descriptor_table.cpp | 5 +--- .../generic_interrupt_handler.cpp | 14 ++++++++++ 13 files changed, 105 insertions(+), 62 deletions(-) create mode 100644 arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp create mode 100644 arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 5242f3d..5e87594 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -106,6 +106,14 @@ target_sources("_context" PRIVATE "src/context_switching/interrupt_descriptor_table/segment_selector.cpp" ) +#[============================================================================[ +# The Interrupt Handlers +#]============================================================================] + +target_sources("_interrupt_handling" PRIVATE + "src/interrupt_handling/generic_interrupt_handler.cpp" +) + #[============================================================================[ # The Bootable ISO Image #]============================================================================] 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 index a652e0c..e677cbb 100644 --- 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 @@ -1,5 +1,5 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#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" @@ -57,15 +57,14 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table private: // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _offset_1 = {}; ///< First part of the offset field. Represents the address of the entry point of the - ///< Interrupt Service Routine. (0 - 15) + 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 = {}; ///< Second part of the offset field. Represents the address of the entry point of - ///< the Interrupt Service Routine. (48 - 95) + uint16_t _offset_2 = {}; ///< Middle 16 bits of handler function address (48 - 63) + uint32_t _offset_3 = {}; ///< Upper 32 bits of handler function address (for x86_64) (64 - 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_INTERRRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#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/interrupt_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp index dd55cd7..e2ec4c5 100644 --- 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 @@ -1,5 +1,5 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#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" @@ -15,4 +15,4 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table } // namespace teachos::arch::context_switching::interrupt_descriptor_table -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#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 index d853ff0..7fe933b 100644 --- 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 @@ -1,5 +1,5 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#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" @@ -23,7 +23,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table /** * @brief Constructor. */ - interrupt_descriptor_table_pointer(uint16_t table_length, interrupt_descriptor_table * address); + interrupt_descriptor_table_pointer(uint16_t table_length, gate_descriptor * address); /** * @brief Defaulted three-way comparsion operator. @@ -31,10 +31,10 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table 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. - interrupt_descriptor_table * address = {}; ///< Non-owning pointer to the IDT base address. + 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_INTERRRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#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/segment_descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp index 764aec5..8217bcb 100644 --- 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 @@ -18,22 +18,16 @@ namespace teachos::arch::context_switching::segment_descriptor_table */ enum bitset : uint8_t { + AVAILABLE = 1U << 0U, ///< Available for use by System software. For our purposes this is basically reserved. 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 bis - ///< is set the DEFAULT_LENGTH bis needs to be 0 + ///< 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 is set the DEFAULT_OPERAND_SIZE/BIG bit needs to be clear (0). - // FIXME: Where does this come from, and is this value correct? - UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 - ///< GiB, 4 KiB otherwise. - - // FIXME: Where does this come from, and is this value correct? - STACK_POINTER_SIZE = 1U << 1U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for - ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. - - // FIXME: Where does this come from, and is this value correct? - DEFAULT_LENGTH = 1U << 1U, ///< Indicates the default length for code segments with effective addresses and - ///< operands. Enable for 32 bit, 16 bit otherwise. + DEFAULT_OPERATION_SIZE = + 1U << 2U, ///< If clear, this is a 16-bit code segment; if set, this is a 32-bit segment. + BIG = 1U << 2U, ///< If set, the maximum offset size for a data segment is increased to 32-bit + ///< 0xffffffff. Otherwise it's the 16-bit max 0x0000ffff. Essentially the same meaning as "D". 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. 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 new file mode 100644 index 0000000..9f33fa0 --- /dev/null +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -0,0 +1,28 @@ +#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 This has been created in a rush. I think it is correct + * + * TODO: Create doxygen + * + */ + struct interrupt_frame + { + uint64_t ip; ///< Dummy + uint64_t cs; ///< Dummy + uint64_t flags; ///< Dummy + uint64_t sp; ///< Dummy + uint64_t ss; ///< Dummy + }; + + [[gnu::interrupt]] + auto generic_interrupt_handler(struct 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/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 108dbe5..38a8af4 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -197,10 +197,8 @@ _start: call enable_paging call enable_sse - cli /* Clears the interrupt flag during the GDT setup */ lgdt (global_descriptor_table_pointer) jmp $global_descriptor_table_code, $_transition_to_long_mode - /* The interrupt flag is set in cpp after setting up the GDT */ call halt @@ -369,14 +367,7 @@ reload_segment_register: ret _transition_to_long_mode: - //call reload_segment_register - - xor %rax, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs + call reload_segment_register movl $0xb8000, (vga_buffer_pointer) diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp index 28f289c..d86c459 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -8,6 +8,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(flags >> 32U) , _flags(flags >> 40U) , _offset_2(flags >> 48U) + , _offset_3(flags >> 64U) { // Nothing to do. } @@ -18,6 +19,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(ist) , _flags(flags) , _offset_2(offset >> 16U) + , _offset_3(offset >> 48U) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index ddc098e..1c1de68 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -1,20 +1,24 @@ #include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/interrupt_handling/generic_interrupt_handler.hpp" #include "arch/kernel/cpu/idtr.hpp" namespace teachos::arch::context_switching::interrupt_descriptor_table { namespace { + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - uint64_t offset = 0U; + // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) + uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL}; - gate_descriptor gate_descriptor{selector, ist, flags, offset}; - return interrupt_descriptor_table{gate_descriptor}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; + gate_descriptor descriptor{selector, ist, flags, offset}; + + return interrupt_descriptor_table{descriptor}; } } // namespace @@ -24,7 +28,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table static auto idt = create_interrupt_descriptor_table(); interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), - &idt}; + idt.data()}; kernel::cpu::load_interrupt_descriptor_table(idt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp index 981944d..7bcbae6 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -3,7 +3,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - interrupt_descriptor_table * address) + gate_descriptor * address) : table_length(table_length) , address(address) { diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index a5bd3fb..f449a3a 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -10,24 +10,30 @@ namespace teachos::arch::context_switching { auto initialize_descriptor_tables() -> descriptor_tables { + kernel::cpu::clear_interrupt_flag(); decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - kernel::cpu::far_pointer pointer{&boot::reload_segment_register, 1 * sizeof(segment_descriptor_table::segment_descriptor)}; - asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m" (pointer)); + kernel::cpu::far_pointer pointer{&boot::reload_segment_register, + 1 * sizeof(segment_descriptor_table::segment_descriptor)}; + asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m"(pointer)); - // // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // // offset in bytes to the start of the segment descriptor (5 * 16) = 80 - // uint16_t const tss_selector = - // (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); - // kernel::cpu::load_task_register(tss_selector); + // Load task state segment descriptor from the last element in the global descriptor table, done by calculating + // offset in bytes to the start of the segment descriptor (5 * 16) = 80 + uint16_t const tss_selector = + (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + kernel::cpu::load_task_register(tss_selector); - // auto const stored_task_register = kernel::cpu::store_task_register(); - // arch::exception_handling::assert(tss_selector == stored_task_register, - // "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP. Maybe because no IDT is loaded? Maybe our boot code segment is not set up correctly? - // kernel::cpu::set_interrupt_flag(); + // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP + // and triple fault. + + // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the + // idt). NEVER happened when stepping through quickly. Can you reproduce this? + kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; return tables; diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index 37ee778..d9ad91c 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -17,17 +17,14 @@ namespace teachos::arch::context_switching::segment_descriptor_table { uint8_t access_level_bits = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT | *reinterpret_cast(&access_level); - uint8_t gdt_flags_bits = gdt_flags::GRANULARITY; + uint8_t gdt_flags_bits = gdt_flags::GRANULARITY | gdt_flags::LONG_MODE; if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) { - gdt_flags_bits |= gdt_flags::LONG_MODE; access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { gdt_flags_bits |= 1 << 2; - // FIXME: Look at those bit flags, something seems off. - // gdt_flags_bits |= gdt_flags::UPPER_BOUND; access_level_bits |= access_byte::WRITABLE; } diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp new file mode 100644 index 0000000..68b4568 --- /dev/null +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -0,0 +1,14 @@ +#include "arch/interrupt_handling/generic_interrupt_handler.hpp" + +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::interrupt_handling +{ + + [[gnu::interrupt]] + auto generic_interrupt_handler(interrupt_frame * frame) -> void + { + (void)frame; + video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); + } +} // namespace teachos::arch::interrupt_handling \ No newline at end of file -- cgit v1.2.3 From 8d16dcb672c4b5f4b0a12ef2eac3486f1b2bb316 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 29 Mar 2025 14:47:23 +0000 Subject: remove empty line --- arch/x86_64/src/context_switching/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index f449a3a..008da2f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -30,7 +30,6 @@ namespace teachos::arch::context_switching // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. - // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); -- cgit v1.2.3 From abe7bd7480c8f4e1e30b9f0f3b98966222817f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 10:38:53 +0000 Subject: Clean up global descriptor table initalization --- .../interrupt_descriptor_table/gate_descriptor.hpp | 3 +- .../interrupt_descriptor_table.hpp | 12 +++-- .../segment_descriptor_table/gdt_flags.hpp | 15 +++--- .../global_descriptor_table.hpp | 24 +++++++-- arch/x86_64/include/arch/kernel/cpu/jmp.hpp | 3 +- .../interrupt_descriptor_table/gate_descriptor.cpp | 2 - .../interrupt_descriptor_table.cpp | 31 +++++------ arch/x86_64/src/context_switching/main.cpp | 23 ++++----- .../global_descriptor_table.cpp | 60 +++++++++++++--------- .../generic_interrupt_handler.cpp | 2 +- arch/x86_64/src/kernel/cpu/jmp.cpp | 2 +- 11 files changed, 100 insertions(+), 77 deletions(-) (limited to 'arch') 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 index e677cbb..22cd0f0 100644 --- 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 @@ -61,8 +61,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table 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) - uint16_t _offset_2 = {}; ///< Middle 16 bits of handler function address (48 - 63) - uint32_t _offset_3 = {}; ///< Upper 32 bits of handler function address (for x86_64) (64 - 95) + 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 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 index e2ec4c5..b388e0e 100644 --- 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 @@ -6,12 +6,18 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { /** - * @brief Initializes the interrupt_descriptor_table by loading it - * in the IDTR register. + * @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 initialize_interrupt_descriptor_table() -> interrupt_descriptor_table &; + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &; } // namespace teachos::arch::context_switching::interrupt_descriptor_table 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 index 8217bcb..d8c3cd1 100644 --- 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 @@ -18,17 +18,16 @@ namespace teachos::arch::context_switching::segment_descriptor_table */ enum bitset : uint8_t { - AVAILABLE = 1U << 0U, ///< Available for use by System software. For our purposes this is basically reserved. 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 is set the DEFAULT_OPERAND_SIZE/BIG bit needs to be clear (0). - - DEFAULT_OPERATION_SIZE = - 1U << 2U, ///< If clear, this is a 16-bit code segment; if set, this is a 32-bit segment. - BIG = 1U << 2U, ///< If set, the maximum offset size for a data segment is increased to 32-bit - ///< 0xffffffff. Otherwise it's the 16-bit max 0x0000ffff. Essentially the same meaning as "D". - + ///< 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. }; 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 index f3067ba..bd69a46 100644 --- 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 @@ -7,12 +7,30 @@ namespace teachos::arch::context_switching::segment_descriptor_table { /** - * @brief Initializes the global_descriptor_table and task_state_segment by loading them - * in the GDTR and TR registers respectively. + * @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 initialize_global_descriptor_table() -> global_descriptor_table &; + auto get_or_create_global_descriptor_table() -> 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_global_descriptor_table_register() -> 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_global_descriptor_table_register() and a far jump has been + * executed. Because before that trying to access the segment will cause an exception. + */ + auto update_task_state_segment_register() -> void; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp index 0ed38e9..1657c18 100644 --- a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp @@ -13,7 +13,8 @@ namespace teachos::arch::kernel::cpu struct far_pointer { void (*function)(); ///< Address of the function we want to jump too. (0-63) - std::uint16_t index; ///< Index of the GDT entry we want to load into register CS. (64-79) + context_switching::interrupt_descriptor_table::segment_selector + selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79) }; /** diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp index d86c459..28f289c 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -8,7 +8,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(flags >> 32U) , _flags(flags >> 40U) , _offset_2(flags >> 48U) - , _offset_3(flags >> 64U) { // Nothing to do. } @@ -19,7 +18,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(ist) , _flags(flags) , _offset_2(offset >> 16U) - , _offset_3(offset >> 48U) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 1c1de68..62b116b 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -6,26 +6,23 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { - namespace + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & { + // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) + uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; + gate_descriptor descriptor{selector, ist, flags, offset}; - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table - { - // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) - uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; - gate_descriptor descriptor{selector, ist, flags, offset}; - - return interrupt_descriptor_table{descriptor}; - } - } // namespace + // Interrupt Descriptor Table needs to be kept alive + static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; + return interrupt_descriptor_table; + } - auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table & + auto update_interrupt_descriptor_table_register() -> void { - // Interrupt Descriptor Table needs to be kept alive - static auto idt = create_interrupt_descriptor_table(); + static auto idt = get_or_create_interrupt_descriptor_table(); interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), idt.data()}; @@ -35,7 +32,5 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table arch::exception_handling::assert( idt_pointer == stored_gdt_pointer, "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); - - return idt; } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 008da2f..db04b52 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -11,22 +11,16 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { kernel::cpu::clear_interrupt_flag(); - decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); - decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - kernel::cpu::far_pointer pointer{&boot::reload_segment_register, - 1 * sizeof(segment_descriptor_table::segment_descriptor)}; - asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m"(pointer)); + segment_descriptor_table::update_global_descriptor_table_register(); + interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // offset in bytes to the start of the segment descriptor (5 * 16) = 80 - uint16_t const tss_selector = - (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); - kernel::cpu::load_task_register(tss_selector); + interrupt_descriptor_table::segment_selector segment_selector{ + 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; + kernel::cpu::jmp(pointer); - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + segment_descriptor_table::update_task_state_segment_register(); // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. @@ -34,7 +28,8 @@ namespace teachos::arch::context_switching // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); - descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; + descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index d9ad91c..346db9e 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -24,7 +24,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - gdt_flags_bits |= 1 << 2; + gdt_flags_bits |= gdt_flags::UPPER_BOUND; access_level_bits |= access_byte::WRITABLE; } @@ -46,33 +46,33 @@ namespace teachos::arch::context_switching::segment_descriptor_table TSS_LIMIT}; return tss_descriptor; } + } // namespace - auto create_global_descriptor_table() -> global_descriptor_table - { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + auto get_or_create_global_descriptor_table() -> global_descriptor_table & + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } - } // namespace + // Global Descriptor Table needs to be kept alive + static global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } - auto initialize_global_descriptor_table() -> global_descriptor_table & + auto update_global_descriptor_table_register() -> void { - // Global Descriptor Table needs to be kept alive - static auto gdt = create_global_descriptor_table(); + decltype(auto) gdt = get_or_create_global_descriptor_table(); // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. @@ -84,8 +84,20 @@ namespace teachos::arch::context_switching::segment_descriptor_table arch::exception_handling::assert( gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + } + + auto update_task_state_segment_register() -> void + { + decltype(auto) gdt = get_or_create_global_descriptor_table(); + + // Load task state segment descriptor from the last element in the global descriptor table, done by calculating + // offset in bytes to the start of the segment descriptor (5 * 16) = 80 + uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + kernel::cpu::load_task_register(tss_selector); - return gdt; + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); } } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 68b4568..2f599e5 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -11,4 +11,4 @@ namespace teachos::arch::interrupt_handling (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } -} // namespace teachos::arch::interrupt_handling \ No newline at end of file +} // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 0c94693..2833219 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -9,6 +9,6 @@ namespace teachos::arch::kernel::cpu auto jmp(far_pointer pointer) -> void { - asm volatile("rex64 ljmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From e8fb1d771d9aa4d1cb5b18cd0483c7e5731aeecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 13:18:56 +0000 Subject: Improve create_segment readability --- .../interrupt_descriptor_table/idt_flags.hpp | 15 ++++-- .../segment_selector.hpp | 15 ++++-- .../segment_descriptor_table/access_byte.hpp | 19 ++++--- .../segment_descriptor_table/gdt_flags.hpp | 15 ++++-- .../interrupt_descriptor_table/idt_flags.cpp | 2 + .../interrupt_descriptor_table.cpp | 28 ++++++---- .../segment_selector.cpp | 2 + arch/x86_64/src/context_switching/main.cpp | 2 - .../segment_descriptor_table/access_byte.cpp | 2 + .../segment_descriptor_table/gdt_flags.cpp | 2 + .../global_descriptor_table.cpp | 62 ++++++++++++---------- 11 files changed, 106 insertions(+), 58 deletions(-) (limited to 'arch') 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 index f153e36..2f8e61d 100644 --- 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 @@ -48,13 +48,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table idt_flags(uint8_t flags); /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * @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 - * std::bitset. Any additional bits that are set are not relevant. + * data. 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. + * @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; @@ -66,6 +66,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table */ 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. }; 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 index 73cd176..2c90152 100644 --- 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 @@ -51,13 +51,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table segment_selector(uint16_t index, uint8_t flags); /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * @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 - * std::bitset. Any additional bits that are set are not relevant. + * data. 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. + * @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; @@ -66,6 +66,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table */ 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; + private: uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. uint16_t _index : 13 = 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 index 3d7862c..621b570 100644 --- 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 @@ -71,24 +71,31 @@ namespace teachos::arch::context_switching::segment_descriptor_table access_byte(uint8_t flags); /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * @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 - * std::bitset. Any additional bits that are set are not relevant. + * data. 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. + * @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 std::bitset of two instances. + * @brief Allows to compare the underlying data 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. + * @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. }; 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 index d8c3cd1..4b84035 100644 --- 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 @@ -50,13 +50,13 @@ namespace teachos::arch::context_switching::segment_descriptor_table gdt_flags(uint8_t flags, std::bitset<20U> limit); /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * @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 - * std::bitset. Any additional bits that are set are not relevant. + * data. 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. + * @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; @@ -77,6 +77,13 @@ namespace teachos::arch::context_switching::segment_descriptor_table */ 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. diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp index e7379ef..d36a4c1 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp @@ -12,4 +12,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { return (std::bitset<8U>{_flags} & other) == other; } + + auto idt_flags::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 62b116b..db3351e 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -6,18 +6,28 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & + namespace { - // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) - uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; - gate_descriptor descriptor{selector, ist, flags, offset}; + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table + { + // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) + uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; + gate_descriptor descriptor{selector, ist, flags, offset}; + + // Interrupt Descriptor Table needs to be kept alive + static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; + return interrupt_descriptor_table; + } + } // namespace + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & + { // Interrupt Descriptor Table needs to be kept alive - static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; - return interrupt_descriptor_table; + static interrupt_descriptor_table idt = create_interrupt_descriptor_table(); + return idt; } auto update_interrupt_descriptor_table_register() -> void diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp index 494e50f..62aed9b 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -13,4 +13,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { return (std::bitset<3U>{_flags} & other) == other; } + + auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index db04b52..2b853ec 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -24,8 +24,6 @@ namespace teachos::arch::context_switching // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. - // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the - // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp index 34a10f1..e31e021 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp @@ -12,4 +12,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table { return (std::bitset<8U>{_flags} & other) == other; } + + auto access_byte::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp index 9885bda..e444a24 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp @@ -15,4 +15,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table } auto gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } + + auto gdt_flags::operator|=(std::bitset<4U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index 346db9e..a497632 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -11,28 +11,26 @@ namespace teachos::arch::context_switching::segment_descriptor_table { namespace { - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level) -> segment_descriptor { - uint8_t access_level_bits = - access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT | *reinterpret_cast(&access_level); - uint8_t gdt_flags_bits = gdt_flags::GRANULARITY | gdt_flags::LONG_MODE; + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + gdt_flags flags{gdt_flags::GRANULARITY, limit}; + + access_level |= access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) { - access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; + flags |= gdt_flags::LONG_MODE; + access_level |= access_byte::CODE_SEGMENT | access_byte::READABLE; } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - gdt_flags_bits |= gdt_flags::UPPER_BOUND; - access_level_bits |= access_byte::WRITABLE; + flags |= gdt_flags::UPPER_BOUND; + access_level |= access_byte::WRITABLE; } - uint64_t const base = 0x0; - std::bitset<20U> const limit{0xFFFFF}; - access_byte const access_byte{access_level_bits}; - gdt_flags const gdt_flags{gdt_flags_bits, limit}; - segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + segment_descriptor const segment_descriptor{access_level, flags, base, limit}; return segment_descriptor; } @@ -46,28 +44,34 @@ namespace teachos::arch::context_switching::segment_descriptor_table TSS_LIMIT}; return tss_descriptor; } + + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); + + global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } } // namespace auto get_or_create_global_descriptor_table() -> global_descriptor_table & { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - // Global Descriptor Table needs to be kept alive - static global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; + static global_descriptor_table gdt = create_global_descriptor_table(); + return gdt; } auto update_global_descriptor_table_register() -> void -- cgit v1.2.3 From 40cfa485cc2c9e344a0386419ed55c123312ec32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 15:20:27 +0000 Subject: Add missing flag to idt entry. --- .../interrupt_descriptor_table.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index db3351e..b520a57 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -10,15 +10,20 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) - uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + // TODO: See 7.14 Vol. 3A Page 3299 Intel Manual, still crashes from time to time on setting interrupt flag? + // Probably an interrupt is generated but the interrupt descriptor table is not in a valid form and does not + // handle the interrupt. + interrupt_descriptor_table interrupt_descriptor_table{256}; + + uint64_t offset = 0U; + segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; - gate_descriptor descriptor{selector, ist, flags, offset}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - // Interrupt Descriptor Table needs to be kept alive - static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; + for (std::size_t i = 0; i < 256; i++) + { + interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; + } return interrupt_descriptor_table; } } // namespace @@ -32,7 +37,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto update_interrupt_descriptor_table_register() -> void { - static auto idt = get_or_create_interrupt_descriptor_table(); + decltype(auto) idt = get_or_create_interrupt_descriptor_table(); interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), idt.data()}; -- cgit v1.2.3 From 6878ffae67a6940ab8dca9831abf9537322ed2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 1 Apr 2025 13:35:49 +0000 Subject: Fix invalid type field of gate descriptor --- .../arch/context_switching/interrupt_descriptor_table/idt_flags.hpp | 4 ++-- .../arch/context_switching/interrupt_descriptor_table/ist_offset.hpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'arch') 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 index 2f8e61d..4e8b32c 100644 --- 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 @@ -18,8 +18,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table */ enum bitset : uint8_t { - INTERRUPT_GATE = 16U, ///< The actual type of gate segment is a interrupt gate. - TRAP_GATE = 17U, ///< The actual type of gate segment is a trap gate. + INTERRUPT_GATE = 0b1110, ///< The actual type of gate segment is a interrupt gate. + TRAP_GATE = 0b1111, ///< 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 = 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 index f31a898..cefe1b2 100644 --- 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 @@ -34,7 +34,9 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto operator==(ist_offset const & other) const -> bool = default; private: - uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. + uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. A value of of 0 menas 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 -- cgit v1.2.3 From fc4a2306b803ccfc27f1bdc4a831176a5278a9d5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 2 Apr 2025 09:57:54 +0000 Subject: fix interrupt handler and idt --- .../arch/interrupt_handling/generic_interrupt_handler.hpp | 11 ++++++----- .../include/arch/memory/multiboot/elf_symbols_section.hpp | 2 +- arch/x86_64/scripts/kernel.ld | 5 +++++ .../interrupt_descriptor_table.cpp | 13 ++++++------- arch/x86_64/src/context_switching/main.cpp | 2 -- .../src/interrupt_handling/generic_interrupt_handler.cpp | 2 +- 6 files changed, 19 insertions(+), 16 deletions(-) (limited to 'arch') 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 index 9f33fa0..d828c50 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -13,11 +13,12 @@ namespace teachos::arch::interrupt_handling */ struct interrupt_frame { - uint64_t ip; ///< Dummy - uint64_t cs; ///< Dummy - uint64_t flags; ///< Dummy - uint64_t sp; ///< Dummy - uint64_t ss; ///< Dummy + uint64_t error_code; ///< Error Code (TODO: Potential mistake -> some interrupts contain this field and some dont?) + uint64_t ip; ///< Instruction pointer + uint64_t cs; ///< Code segment + uint64_t flags; ///< RFLAGS + uint64_t sp; ///< Stack pointer + uint64_t ss; ///< Stack segment }; [[gnu::interrupt]] 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 730bcaf..0a25ca9 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 @@ -20,7 +20,7 @@ namespace teachos::arch::memory::multiboot 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 deubbging null-terminated strings. + 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. diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index cc07896..806adb5 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -90,6 +90,11 @@ SECTIONS *(.text*) } + .interrupt_text ALIGN(4K) : AT(ADDR (.interrupt_text)) + { + *(.interrupt_text) + } + .rodata ALIGN(4K) : AT (ADDR (.rodata)) { *(.rodata) diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index b520a57..82114b4 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -10,20 +10,19 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // TODO: See 7.14 Vol. 3A Page 3299 Intel Manual, still crashes from time to time on setting interrupt flag? - // Probably an interrupt is generated but the interrupt descriptor table is not in a valid form and does not - // handle the interrupt. - interrupt_descriptor_table interrupt_descriptor_table{256}; + // Only account for the reserved Vectors for now (0 - 31) + interrupt_descriptor_table interrupt_descriptor_table{32}; - uint64_t offset = 0U; - segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; + uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); + segment_selector selector{2U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - for (std::size_t i = 0; i < 256; i++) + for (std::size_t i = 0; i < 32; i++) { interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } + return interrupt_descriptor_table; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 2b853ec..ac53735 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -22,8 +22,6 @@ namespace teachos::arch::context_switching segment_descriptor_table::update_task_state_segment_register(); - // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP - // and triple fault. kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 2f599e5..4392b04 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -5,7 +5,7 @@ namespace teachos::arch::interrupt_handling { - [[gnu::interrupt]] + [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto generic_interrupt_handler(interrupt_frame * frame) -> void { (void)frame; -- cgit v1.2.3 From f19681f4dfaaa0bdd3f22e76c48abda3c68bfe0c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 3 Apr 2025 08:59:50 +0000 Subject: add documentation to interrupt handler --- .../generic_interrupt_handler.hpp | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'arch') 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 index d828c50..6c1db12 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -6,21 +6,26 @@ namespace teachos::arch::interrupt_handling { /** - * @brief This has been created in a rush. I think it is correct - * - * TODO: Create doxygen + * @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 interrupt_frame + struct [[gnu::packed]] interrupt_frame { - uint64_t error_code; ///< Error Code (TODO: Potential mistake -> some interrupts contain this field and some dont?) - uint64_t ip; ///< Instruction pointer - uint64_t cs; ///< Code segment - uint64_t flags; ///< RFLAGS - uint64_t sp; ///< Stack pointer - uint64_t ss; ///< Stack segment + uint64_t error_code; ///< Error code pushed by some exceptions. + 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(struct interrupt_frame * frame) -> void; -- cgit v1.2.3 From 8b66e4cd1d1487fefbae459f556396db61497a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 4 Apr 2025 15:05:59 +0000 Subject: Multiplication by two for segment selector index --- .../interrupt_descriptor_table/segment_selector.hpp | 8 ++++++-- .../interrupt_descriptor_table/segment_selector.cpp | 2 +- arch/x86_64/src/context_switching/main.cpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'arch') 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 index 2c90152..b31f9e8 100644 --- 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 @@ -43,8 +43,12 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table /** * @brief Constructor. * - * @param index 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. + * @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. Because it only + * multiplies by 8, but we are using long mode the constructor additionally multiplies the given value by two. This + * is done because 64-bit segment descriptor are twice as big in size. If we wouldn't multiply by two, index 1 would + * result in the middle between the second part of the null entry and the first part of the code kernel segment and + * therefore be invalid. * @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. */ diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp index 62aed9b..b1b316d 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { segment_selector::segment_selector(uint16_t index, uint8_t flags) : _flags(flags) - , _index(index) + , _index(index * 2U) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index ac53735..6614065 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -16,7 +16,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::update_interrupt_descriptor_table_register(); interrupt_descriptor_table::segment_selector segment_selector{ - 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; kernel::cpu::jmp(pointer); -- cgit v1.2.3 From c01d080bdc6bd843e840e4834424fe587286b274 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 5 Apr 2025 12:04:12 +0000 Subject: fix segment_selector --- .../interrupt_descriptor_table/interrupt_descriptor_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 82114b4..9b62110 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table interrupt_descriptor_table interrupt_descriptor_table{32}; uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); - segment_selector selector{2U, segment_selector::REQUEST_LEVEL_KERNEL}; + segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; -- cgit v1.2.3 From a8852f91967a7e55e62e30f5cc07d076092b8b78 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 5 Apr 2025 15:27:20 +0000 Subject: add wip context switch to user mode --- arch/x86_64/CMakeLists.txt | 2 +- arch/x86_64/include/arch/boot/pointers.hpp | 5 ---- .../include/arch/kernel/cpu/segment_register.hpp | 23 ++++++++++++++ arch/x86_64/include/arch/kernel/cpu/ss.hpp | 27 ----------------- arch/x86_64/src/boot/boot.s | 11 +------ arch/x86_64/src/context_switching/main.cpp | 4 +-- arch/x86_64/src/kernel/cpu/segment_register.cpp | 34 +++++++++++++++++++++ arch/x86_64/src/kernel/cpu/ss.cpp | 16 ---------- arch/x86_64/src/kernel/main.cpp | 35 ++++++++++++++++++++++ 9 files changed, 96 insertions(+), 61 deletions(-) create mode 100644 arch/x86_64/include/arch/kernel/cpu/segment_register.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/ss.hpp create mode 100644 arch/x86_64/src/kernel/cpu/segment_register.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/ss.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 5e87594..0d52463 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -13,7 +13,7 @@ target_sources("_kernel" PRIVATE "src/kernel/cpu/if.cpp" "src/kernel/cpu/jmp.cpp" "src/kernel/cpu/msr.cpp" - "src/kernel/cpu/ss.cpp" + "src/kernel/cpu/segment_register.cpp" "src/kernel/cpu/tlb.cpp" "src/kernel/cpu/tr.cpp" ) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 9bf5cfd..fe9c657 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -10,11 +10,6 @@ namespace teachos::arch::boot */ extern "C" size_t const multiboot_information_pointer; - /** - * @brief Address pointing to the method that clears all segment registers. - */ - extern "C" void reload_segment_register(); - } // namespace teachos::arch::boot #endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp new file mode 100644 index 0000000..bd244fd --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -0,0 +1,23 @@ +#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 segment registers. + */ + [[gnu::naked]] + auto reload_segment_registers() -> void; + + /** + * @brief Set the value of all segment registers. + * + * @param segment_selector + */ + auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> 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/ss.hpp b/arch/x86_64/include/arch/kernel/cpu/ss.hpp deleted file mode 100644 index b5fa5e3..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/ss.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Reads the current value of the stack segment (SS) register. - * - * @return The current SS register value. - */ - auto read_ss() -> context_switching::interrupt_descriptor_table::segment_selector; - - /** - * @brief Writes a new value to the stack segment (SS) register. - * - * @param selector The segment selector to be written to SS. - */ - auto write_ss(context_switching::interrupt_descriptor_table::segment_selector selector) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 38a8af4..7932045 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,11 +352,7 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global reload_segment_register -reload_segment_register: - // FIXME: maybe we should set the actually correct values here. We'd need to communicate them down from C++. - // Alternatively, we could probably implement this as a [[gnu::naked]] function in C++, to have easier access to - // arguments and symbols. Maybe later. +_transition_to_long_mode: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -364,11 +360,6 @@ reload_segment_register: mov %rax, %fs mov %rax, %gs - ret - -_transition_to_long_mode: - call reload_segment_register - movl $0xb8000, (vga_buffer_pointer) call _init diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 6614065..124df93 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,9 +1,9 @@ #include "arch/context_switching/main.hpp" -#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" namespace teachos::arch::context_switching @@ -17,7 +17,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; + kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; kernel::cpu::jmp(pointer); segment_descriptor_table::update_task_state_segment_register(); diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp new file mode 100644 index 0000000..f70c558 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -0,0 +1,34 @@ +#include "arch/kernel/cpu/segment_register.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +namespace teachos::arch::kernel::cpu +{ + [[gnu::naked]] + auto reload_segment_registers() -> void + { + asm volatile("xor %rax, %rax\n" + "mov %rax, %ss\n" + "mov %rax, %ds\n" + "mov %rax, %es\n" + "mov %rax, %fs\n" + "mov %rax, %gs\n" + "ret"); + } + + [[gnu::naked]] + auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + { + asm volatile("xor %%rax, %%rax\n" + "mov %[input], %%ax\n" + "mov %%rax, %%ss\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "ret" + : /* No output from call */ + : [input] "m"(segment_selector)); + } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp deleted file mode 100644 index 0978eca..0000000 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/kernel/cpu/ss.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto read_ss() -> context_switching::interrupt_descriptor_table::segment_selector - { - context_switching::interrupt_descriptor_table::segment_selector segment_selector{}; - asm volatile("mov %%ss, %[output]" : [output] "=m"(segment_selector)); - return segment_selector; - } - - auto write_ss(context_switching::interrupt_descriptor_table::segment_selector selector) -> void - { - asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "m"(selector)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7782d30..7d4173e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,9 +1,11 @@ #include "arch/kernel/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" #include "arch/context_switching/main.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -49,6 +51,23 @@ namespace teachos::arch::kernel delete test9; } + [[gnu::naked]] + auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + { + asm volatile("push %%rbp\n" + "push %[input]" + : /* No output from call */ + : [input] "m"(segment_selector)); + } + + [[gnu::naked]] + auto iret() -> void + { + asm volatile("iret" + : /* No output from call */ + : /* No input to call */); + } + auto main() -> void { video::vga::text::clear(); @@ -64,6 +83,22 @@ namespace teachos::arch::kernel heap_test(); decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); + + // - Clear NT flag in EFLAGS register (for far return) + + // - Push return instruction pointer + // - Push return code segment selector + context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + push_code_segment(user_code_segment_selector); + + context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + kernel::cpu::set_segment_registers(user_data_segment_selector); + + // IRET + iret(); + (void)descriptor_tables; } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 350aedae0e50749f9821ac7dc6b8316cf35f24bb Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 6 Apr 2025 07:47:27 +0000 Subject: wip context switch in asm --- arch/x86_64/include/arch/boot/pointers.hpp | 1 + arch/x86_64/src/boot/boot.s | 29 ++++++++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 31 +++++++++++++++++++----------- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index fe9c657..f0878f9 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -9,6 +9,7 @@ namespace teachos::arch::boot * @brief Address pointing to the start of the multiboot information structure. */ extern "C" size_t const multiboot_information_pointer; + extern "C" auto context_switch() -> void; } // namespace teachos::arch::boot diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..85ae1a1 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,6 +352,35 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +.global context_switch +context_switch: + // ring 3 data with bottom 2 bits set for ring 3 + mov $((4 * 16) | 3), %rax + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + // SS is handled by iret https://wiki.osdev.org/Getting_to_Ring_3 + + // set up the stack frame iret expects + mov %rsp, %rax + // user data selector + push $((4 * 16) | 3) + // current exp + push %rax + // push eflags + pushf + // push code selector (ring 3 code with bottom 2 bits set for ring 3) + push $((3 * 16) | 3) + // instruction address to return to + push test_function + + iret + +test_function: + cli + ret + _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7d4173e..52799f0 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -52,12 +52,24 @@ namespace teachos::arch::kernel } [[gnu::naked]] - auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector_a, + context_switching::interrupt_descriptor_table::segment_selector segment_selector_b) -> void { asm volatile("push %%rbp\n" "push %[input]" : /* No output from call */ - : [input] "m"(segment_selector)); + : [input] "m"(segment_selector_a)); + asm volatile("mov %[input], %%ax\n" + "mov %%ax, %%ss\n" + "mov %%ax, %%ds\n" + "mov %%ax, %%es\n" + "mov %%ax, %%fs\n" + "mov %%ax, %%gs" + : /* No output from call */ + : [input] "m"(segment_selector_b)); + asm volatile("iret" + : /* No output from call */ + : /* No input to call */); } [[gnu::naked]] @@ -88,16 +100,13 @@ namespace teachos::arch::kernel // - Push return instruction pointer // - Push return code segment selector - context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ - 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - push_code_segment(user_code_segment_selector); - - context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - kernel::cpu::set_segment_registers(user_data_segment_selector); + // context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ + // 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + // context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ + // 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + // push_code_segment(user_code_segment_selector, user_data_segment_selector); - // IRET - iret(); + boot::context_switch(); (void)descriptor_tables; } -- cgit v1.2.3 From 3a95e601bbcb64fd80d9d5d9bd6e1f6d3c31a89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 7 Apr 2025 15:05:30 +0000 Subject: Adjust idt flags bitset --- .../arch/context_switching/interrupt_descriptor_table/idt_flags.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') 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 index 4e8b32c..948f478 100644 --- 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 @@ -18,8 +18,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table */ enum bitset : uint8_t { - INTERRUPT_GATE = 0b1110, ///< The actual type of gate segment is a interrupt gate. - TRAP_GATE = 0b1111, ///< The actual type of gate segment is a trap gate. + 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 = -- cgit v1.2.3 From 8a23a47425162894141f4eac488fb1f1bb3f7dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 7 Apr 2025 15:42:38 +0000 Subject: Fix naming from jmp to call for Far Call --- arch/x86_64/CMakeLists.txt | 2 +- arch/x86_64/include/arch/kernel/cpu/call.hpp | 30 ++++++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/jmp.hpp | 37 ---------------------------- arch/x86_64/src/context_switching/main.cpp | 4 +-- arch/x86_64/src/kernel/cpu/call.cpp | 9 +++++++ arch/x86_64/src/kernel/cpu/jmp.cpp | 14 ----------- arch/x86_64/src/kernel/main.cpp | 1 - 7 files changed, 42 insertions(+), 55 deletions(-) create mode 100644 arch/x86_64/include/arch/kernel/cpu/call.hpp delete mode 100644 arch/x86_64/include/arch/kernel/cpu/jmp.hpp create mode 100644 arch/x86_64/src/kernel/cpu/call.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/jmp.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 0d52463..8f5b9bd 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -11,7 +11,7 @@ target_sources("_kernel" PRIVATE "src/kernel/cpu/gdtr.cpp" "src/kernel/cpu/idtr.cpp" "src/kernel/cpu/if.cpp" - "src/kernel/cpu/jmp.cpp" + "src/kernel/cpu/call.cpp" "src/kernel/cpu/msr.cpp" "src/kernel/cpu/segment_register.cpp" "src/kernel/cpu/tlb.cpp" diff --git a/arch/x86_64/include/arch/kernel/cpu/call.hpp b/arch/x86_64/include/arch/kernel/cpu/call.hpp new file mode 100644 index 0000000..3c43304 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/call.hpp @@ -0,0 +1,30 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +#include + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Far Pointer. Address to function located in another code segment. + */ + struct far_pointer + { + void (*function)(); ///< Address of the function we want to call. (0-63) + context_switching::interrupt_descriptor_table::segment_selector + selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79) + }; + + /** + * @brief Far call - A call to an instruction located in a different segment than the current code segment but at the + * same privilege level. + * + * @param pointer 64-bit operand size far pointer that we want to call. + */ + auto call(far_pointer pointer) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp deleted file mode 100644 index 1657c18..0000000 --- a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp +++ /dev/null @@ -1,37 +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 jump - A jump to an instruction located in a different segment. - */ - struct far_pointer - { - void (*function)(); ///< Address of the function we want to jump too. (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 Near jump - A jump to an instruction within the current code segment. - * - * @param address Address we want to jump to. - */ - auto jmp(std::size_t address) -> void; - - /** - * @brief Far jump - A jump 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 should jump too. - */ - auto jmp(far_pointer pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 124df93..762445f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,8 +1,8 @@ #include "arch/context_switching/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -18,7 +18,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; - kernel::cpu::jmp(pointer); + kernel::cpu::call(pointer); segment_descriptor_table::update_task_state_segment_register(); diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp new file mode 100644 index 0000000..98fa248 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -0,0 +1,9 @@ +#include "arch/kernel/cpu/call.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto call(far_pointer pointer) -> void + { + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp deleted file mode 100644 index 2833219..0000000 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "arch/kernel/cpu/jmp.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto jmp(std::size_t address) -> void - { - asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); - } - - auto jmp(far_pointer pointer) -> void - { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 52799f0..7787f30 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -4,7 +4,6 @@ #include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" #include "arch/context_switching/main.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" -- cgit v1.2.3 From f3d84e8645e1f6318c7e34f3524cd332ac6deef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 07:55:30 +0000 Subject: Remove zombie code --- arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'arch') 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 da3c8ff..377533c 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 @@ -116,9 +116,6 @@ namespace teachos::arch::memory::heap memory_block * first; ///< First free entry in our memory. stl::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. }; - - extern linked_list_allocator kernel_heap; - } // namespace teachos::arch::memory::heap #endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP -- cgit v1.2.3 From 5a8659adaa54ce9514db72d1e40f33dec88605ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 08:06:50 +0000 Subject: Move interrupt count into seperate variable --- .../interrupt_descriptor_table/interrupt_descriptor_table.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 9b62110..80f01a8 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -8,17 +8,20 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { namespace { + /// @brief Amount of currently reserved interrupt indicies. + /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. + constexpr uint8_t RESERVED_INTERRUPT_COUNT = 32U; + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // Only account for the reserved Vectors for now (0 - 31) - interrupt_descriptor_table interrupt_descriptor_table{32}; + interrupt_descriptor_table interrupt_descriptor_table{RESERVED_INTERRUPT_COUNT}; uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - for (std::size_t i = 0; i < 32; i++) + for (std::size_t i = 0; i < interrupt_descriptor_table.size(); i++) { interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } -- cgit v1.2.3 From 862d7f33414132cb73f7f3968250a071d78c191b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 08:10:10 +0000 Subject: Replace iret with iretq (64-bit) --- arch/x86_64/src/kernel/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7787f30..daaf216 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -66,7 +66,7 @@ namespace teachos::arch::kernel "mov %%ax, %%gs" : /* No output from call */ : [input] "m"(segment_selector_b)); - asm volatile("iret" + asm volatile("iretq" : /* No output from call */ : /* No input to call */); } @@ -74,7 +74,7 @@ namespace teachos::arch::kernel [[gnu::naked]] auto iret() -> void { - asm volatile("iret" + asm volatile("iretq" : /* No output from call */ : /* No input to call */); } -- cgit v1.2.3 From c2d22838c0500970f275069f19d2a0bd2a016d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 09:26:50 +0000 Subject: Also add iretq to boot.s --- arch/x86_64/src/boot/boot.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 85ae1a1..5a49d48 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -375,7 +375,7 @@ context_switch: // instruction address to return to push test_function - iret + iretq test_function: cli -- cgit v1.2.3 From 295f1bc9a29267b72504fffb582a08c2467b1a7f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 09:32:20 +0000 Subject: fix context_switch function --- arch/x86_64/src/boot/boot.s | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 85ae1a1..139fd1a 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,6 +352,10 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +test_function: + cli + ret + .global context_switch context_switch: // ring 3 data with bottom 2 bits set for ring 3 @@ -366,20 +370,17 @@ context_switch: mov %rsp, %rax // user data selector push $((4 * 16) | 3) - // current exp + // current rsp push %rax // push eflags pushf // push code selector (ring 3 code with bottom 2 bits set for ring 3) push $((3 * 16) | 3) - // instruction address to return to - push test_function - - iret + // push instruction address to return to + lea [test_function], %rax + push %rax -test_function: - cli - ret + iretq _transition_to_long_mode: xor %rax, %rax -- cgit v1.2.3 From 62d7fa83e831e84ea851d97b5c957146880ad69a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 10:28:46 +0000 Subject: move context_switch function into cpp code --- arch/x86_64/include/arch/boot/pointers.hpp | 1 - arch/x86_64/src/boot/boot.s | 30 ---------- arch/x86_64/src/kernel/cpu/segment_register.cpp | 1 - arch/x86_64/src/kernel/main.cpp | 76 ++++++++++++++----------- 4 files changed, 44 insertions(+), 64 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index f0878f9..fe9c657 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -9,7 +9,6 @@ namespace teachos::arch::boot * @brief Address pointing to the start of the multiboot information structure. */ extern "C" size_t const multiboot_information_pointer; - extern "C" auto context_switch() -> void; } // namespace teachos::arch::boot diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 139fd1a..7932045 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,36 +352,6 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -test_function: - cli - ret - -.global context_switch -context_switch: - // ring 3 data with bottom 2 bits set for ring 3 - mov $((4 * 16) | 3), %rax - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - // SS is handled by iret https://wiki.osdev.org/Getting_to_Ring_3 - - // set up the stack frame iret expects - mov %rsp, %rax - // user data selector - push $((4 * 16) | 3) - // current rsp - push %rax - // push eflags - pushf - // push code selector (ring 3 code with bottom 2 bits set for ring 3) - push $((3 * 16) | 3) - // push instruction address to return to - lea [test_function], %rax - push %rax - - iretq - _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index f70c558..d7857dd 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -21,7 +21,6 @@ namespace teachos::arch::kernel::cpu { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" - "mov %%rax, %%ss\n" "mov %%rax, %%ds\n" "mov %%rax, %%es\n" "mov %%rax, %%fs\n" diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index daaf216..ac2591e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -50,33 +50,48 @@ namespace teachos::arch::kernel delete test9; } - [[gnu::naked]] - auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector_a, - context_switching::interrupt_descriptor_table::segment_selector segment_selector_b) -> void + auto return_function() -> void { - asm volatile("push %%rbp\n" - "push %[input]" - : /* No output from call */ - : [input] "m"(segment_selector_a)); - asm volatile("mov %[input], %%ax\n" - "mov %%ax, %%ss\n" - "mov %%ax, %%ds\n" - "mov %%ax, %%es\n" - "mov %%ax, %%fs\n" - "mov %%ax, %%gs" - : /* No output from call */ - : [input] "m"(segment_selector_b)); - asm volatile("iretq" - : /* No output from call */ - : /* No input to call */); + video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); } + /** + * @brief Switch context into the mode defined in the segment selectors. + * + * Setup the stack IRETQ expects to switch the mode: + * 1. push data selector + * 2. push current stack pointer + * 3. push eflags + * 4. push code segment selector + * 5. push return address + * + * @param data_segment + * @param code_segment + * @param address + */ [[gnu::naked]] - auto iret() -> void + auto switch_context(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) + -> void { - asm volatile("iretq" - : /* No output from call */ - : /* No input to call */); + asm volatile("mov %[data_segment], %%rax\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "mov %%rsp, %%rax\n" + + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" + + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); } auto main() -> void @@ -95,17 +110,14 @@ namespace teachos::arch::kernel decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); - // - Clear NT flag in EFLAGS register (for far return) - - // - Push return instruction pointer - // - Push return code segment selector - // context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ - // 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - // context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ - // 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - // push_code_segment(user_code_segment_selector, user_data_segment_selector); + context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - boot::context_switch(); + cpu::set_segment_registers(user_data_segment_selector); + switch_context(user_data_segment_selector, user_code_segment_selector, + reinterpret_cast(&return_function)); (void)descriptor_tables; } -- cgit v1.2.3 From dff78de795a89c181e9c94b26db2f16988e8f4d6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 12:11:55 +0000 Subject: move context_switch function and environment into different directory --- .../segment_selector.hpp | 7 ++- .../x86_64/include/arch/context_switching/main.hpp | 24 ++++++++ .../include/arch/kernel/cpu/segment_register.hpp | 9 ++- .../segment_selector.cpp | 7 --- arch/x86_64/src/context_switching/main.cpp | 72 ++++++++++++++++++++++ arch/x86_64/src/kernel/cpu/segment_register.cpp | 9 +++ arch/x86_64/src/kernel/main.cpp | 56 +---------------- 7 files changed, 121 insertions(+), 63 deletions(-) (limited to 'arch') 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 index b31f9e8..e8854f9 100644 --- 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 @@ -52,7 +52,12 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table * @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. */ - segment_selector(uint16_t index, uint8_t flags); + constexpr segment_selector(uint16_t index, uint8_t flags) + : _flags(flags) + , _index(index * 2U) + { + // Nothing to do. + } /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/include/arch/context_switching/main.hpp index d2243ed..e296457 100644 --- a/arch/x86_64/include/arch/context_switching/main.hpp +++ b/arch/x86_64/include/arch/context_switching/main.hpp @@ -15,8 +15,32 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. }; + /** + * @brief Setup GDT and IDT TODO + * + * @return descriptor_tables + */ auto initialize_descriptor_tables() -> descriptor_tables; + /** + * @brief TODO + * + * @param data_segment + * @param code_segment + * @param return_function + */ + auto switch_to_user_mode() -> void; + + /** + * @brief TODO + * + * @param data_segment + * @param code_segment + * @param return_function + */ + 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/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp index bd244fd..fd5a972 100644 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -12,12 +12,19 @@ namespace teachos::arch::kernel::cpu auto reload_segment_registers() -> void; /** - * @brief Set the value of all segment registers. + * @brief Set the value of all segment registers. TODO * * @param segment_selector */ auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void; + /** + * @brief Returns the segment_selector in the code segment (cs) register. TODO + * + * @return segment_selector in the cs register + */ + auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector; + } // namespace teachos::arch::kernel::cpu #endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp index b1b316d..0e29356 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -2,13 +2,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { - segment_selector::segment_selector(uint16_t index, uint8_t flags) - : _flags(flags) - , _index(index * 2U) - { - // Nothing to do. - } - auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool { return (std::bitset<3U>{_flags} & other) == other; diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 762445f..3efba45 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -5,9 +5,59 @@ #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" +#include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching { + namespace + { + + /** + * @brief Switch context into the mode defined in the segment selectors. + * + * Setup the stack IRETQ expects to switch the mode: + * 1. push data selector + * 2. push current stack pointer + * 3. push eflags + * 4. push code segment selector + * 5. push return address + * + * @param data_segment + * @param code_segment + * @param address + */ + [[gnu::naked]] + auto far_return(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) + -> void + { + asm volatile("mov %[data_segment], %%rax\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "mov %%rsp, %%rax\n" + + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" + + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); + } + + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + + } // namespace + auto initialize_descriptor_tables() -> descriptor_tables { kernel::cpu::clear_interrupt_flag(); @@ -28,4 +78,26 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } + + auto user_mode_main() -> void + { + auto current_segment = kernel::cpu::read_code_segment_register(); + arch::exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, + "[Context Switching] Context switch into user mode not successful"); + + video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); + } + + auto switch_to_user_mode() -> void + { + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); + } + + auto switch_context(interrupt_descriptor_table::segment_selector data_segment, + interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void + { + kernel::cpu::set_segment_registers(data_segment); + far_return(data_segment, code_segment, reinterpret_cast(return_function)); + } + } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index d7857dd..9fb7433 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -30,4 +30,13 @@ namespace teachos::arch::kernel::cpu : [input] "m"(segment_selector)); } + auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector + { + context_switching::interrupt_descriptor_table::segment_selector current_value; + asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); + return current_value; + } + + auto validate_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector {} + } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index ac2591e..b69064d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -50,50 +50,6 @@ namespace teachos::arch::kernel delete test9; } - auto return_function() -> void - { - video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); - } - - /** - * @brief Switch context into the mode defined in the segment selectors. - * - * Setup the stack IRETQ expects to switch the mode: - * 1. push data selector - * 2. push current stack pointer - * 3. push eflags - * 4. push code segment selector - * 5. push return address - * - * @param data_segment - * @param code_segment - * @param address - */ - [[gnu::naked]] - auto switch_context(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) - -> void - { - asm volatile("mov %[data_segment], %%rax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - "mov %%rsp, %%rax\n" - - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - - "iretq\n" - : - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - auto main() -> void { video::vga::text::clear(); @@ -109,16 +65,8 @@ namespace teachos::arch::kernel heap_test(); decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); - - context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ - 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - - cpu::set_segment_registers(user_data_segment_selector); - switch_context(user_data_segment_selector, user_code_segment_selector, - reinterpret_cast(&return_function)); - (void)descriptor_tables; + + context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 87091e2246d2c4c794d9d6a0c5398ca80d92335a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 12:29:19 +0000 Subject: add register validation and asserts --- .../include/arch/kernel/cpu/segment_register.hpp | 6 ++++++ arch/x86_64/src/context_switching/main.cpp | 9 ++++++--- arch/x86_64/src/kernel/cpu/segment_register.cpp | 23 +++++++++++++++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp index fd5a972..d495ce6 100644 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -25,6 +25,12 @@ namespace teachos::arch::kernel::cpu */ auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector; + /** + * @brief TODO + * + */ + auto validate_data_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector; + } // namespace teachos::arch::kernel::cpu #endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SEGMENT_REGISTER_HPP diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 3efba45..0f2ec93 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -2,6 +2,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" +#include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -82,10 +83,12 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { auto current_segment = kernel::cpu::read_code_segment_register(); - arch::exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, - "[Context Switching] Context switch into user mode not successful"); + exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, + "[Context Switching] Context switch into user mode not successful"); + exception_handling::assert(USER_DATA_SEGMENT_SELECTOR == kernel::cpu::validate_data_segment_registers(), + "[Context Switching] Context switch into user mode not successful"); - video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } auto switch_to_user_mode() -> void diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 9fb7433..cb367b6 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -1,6 +1,7 @@ #include "arch/kernel/cpu/segment_register.hpp" #include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/exception_handling/assert.hpp" namespace teachos::arch::kernel::cpu { @@ -37,6 +38,26 @@ namespace teachos::arch::kernel::cpu return current_value; } - auto validate_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector {} + auto validate_data_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector + { + context_switching::interrupt_descriptor_table::segment_selector ss; + context_switching::interrupt_descriptor_table::segment_selector ds; + context_switching::interrupt_descriptor_table::segment_selector es; + context_switching::interrupt_descriptor_table::segment_selector fs; + context_switching::interrupt_descriptor_table::segment_selector gs; + + asm volatile( + "mov %%ss, %[ss_output]\n" + "mov %%ds, %[ds_output]\n" + "mov %%es, %[es_output]\n" + "mov %%fs, %[fs_output]\n" + "mov %%gs, %[gs_output]\n" + : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); + + auto result = ss == ds && ss == es && ss == fs && ss == gs; + exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); + + return ss; + } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 9a185c1533bd2197d0e830369b4cc26abf88e2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 09:25:04 +0000 Subject: Document methods and move them into kernel cpu folder --- .../x86_64/include/arch/context_switching/main.hpp | 27 +++++--- .../include/arch/kernel/cpu/segment_register.hpp | 80 +++++++++++++++++++--- arch/x86_64/src/context_switching/main.cpp | 63 ++++------------- arch/x86_64/src/kernel/cpu/segment_register.cpp | 48 +++++++++++-- arch/x86_64/src/kernel/main.cpp | 6 +- 5 files changed, 144 insertions(+), 80 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/include/arch/context_switching/main.hpp index e296457..f8477ea 100644 --- a/arch/x86_64/include/arch/context_switching/main.hpp +++ b/arch/x86_64/include/arch/context_switching/main.hpp @@ -16,27 +16,32 @@ namespace teachos::arch::context_switching }; /** - * @brief Setup GDT and IDT TODO + * @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. * - * @return descriptor_tables + * @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 TODO - * - * @param data_segment - * @param code_segment - * @param return_function + * @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 TODO + * @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 - * @param code_segment - * @param return_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; diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp index d495ce6..5c77206 100644 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -6,30 +6,90 @@ namespace teachos::arch::kernel::cpu { /** - * @brief Clear all segment registers. + * @brief Clear all Data Segment registers (DS / ES / FS / GS). */ - [[gnu::naked]] - auto reload_segment_registers() -> void; + auto reload_data_segment_registers() -> void; /** - * @brief Set the value of all segment registers. TODO + * @brief Updates the value of the Data Segment Register (DS), Extra Segment Register (ES), Thread-Local Storage + * Registers (FS / GS). * - * @param segment_selector + * @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 segment_selector Data Segment that should be loaded into the registers. */ - auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void; + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) + -> void; /** - * @brief Returns the segment_selector in the code segment (cs) register. TODO + * @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 in the cs register + * @return Segment Selector pointing to the currently loaded Code Segment. */ auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector; /** - * @brief TODO + * @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. */ - auto validate_data_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector; + 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 diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 0f2ec93..5cac878 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -12,46 +12,6 @@ namespace teachos::arch::context_switching { namespace { - - /** - * @brief Switch context into the mode defined in the segment selectors. - * - * Setup the stack IRETQ expects to switch the mode: - * 1. push data selector - * 2. push current stack pointer - * 3. push eflags - * 4. push code segment selector - * 5. push return address - * - * @param data_segment - * @param code_segment - * @param address - */ - [[gnu::naked]] - auto far_return(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) - -> void - { - asm volatile("mov %[data_segment], %%rax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - "mov %%rsp, %%rax\n" - - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - - "iretq\n" - : - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ @@ -61,6 +21,14 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { + static bool initalized = false; + if (initalized) + { + descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + return tables; + } + kernel::cpu::clear_interrupt_flag(); segment_descriptor_table::update_global_descriptor_table_register(); @@ -68,7 +36,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; + kernel::cpu::far_pointer pointer{&kernel::cpu::reload_data_segment_registers, segment_selector}; kernel::cpu::call(pointer); segment_descriptor_table::update_task_state_segment_register(); @@ -77,17 +45,13 @@ namespace teachos::arch::context_switching descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + initalized = true; return tables; } auto user_mode_main() -> void { - auto current_segment = kernel::cpu::read_code_segment_register(); - exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, - "[Context Switching] Context switch into user mode not successful"); - exception_handling::assert(USER_DATA_SEGMENT_SELECTOR == kernel::cpu::validate_data_segment_registers(), - "[Context Switching] Context switch into user mode not successful"); - + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } @@ -99,8 +63,9 @@ namespace teachos::arch::context_switching auto switch_context(interrupt_descriptor_table::segment_selector data_segment, interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void { - kernel::cpu::set_segment_registers(data_segment); - far_return(data_segment, code_segment, reinterpret_cast(return_function)); + (void)initialize_descriptor_tables(); + kernel::cpu::set_data_segment_registers(data_segment); + kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index cb367b6..44b4eff 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::kernel::cpu { [[gnu::naked]] - auto reload_segment_registers() -> void + auto reload_data_segment_registers() -> void { asm volatile("xor %rax, %rax\n" "mov %rax, %ss\n" @@ -18,7 +18,8 @@ namespace teachos::arch::kernel::cpu } [[gnu::naked]] - auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) + -> void { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" @@ -38,7 +39,8 @@ namespace teachos::arch::kernel::cpu return current_value; } - auto validate_data_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector + auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) + -> void { context_switching::interrupt_descriptor_table::segment_selector ss; context_switching::interrupt_descriptor_table::segment_selector ds; @@ -54,10 +56,46 @@ namespace teachos::arch::kernel::cpu "mov %%gs, %[gs_output]\n" : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); - auto result = ss == ds && ss == es && ss == fs && ss == gs; + auto result = (ss == ds && ss == es && ss == fs && ss == gs); exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); + result = (ss == data_segment); + exception_handling::assert( + result, "[Segment Register] Expected Data Segment is not the same as the value in the Stack Segment register."); + } + + auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) + -> void + { + auto const cs = read_code_segment_register(); + exception_handling::assert( + cs == code_segment, + "[Segment Register] Expected Code Segment is not the same as the value in the Code Segment register."); + } + + auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void + { + validate_data_segment_registers(data_segment); + validate_code_segment_register(code_segment); + } + + [[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 + { + asm volatile("mov %%rsp, %%rax\n" + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" - return ss; + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index b69064d..05c879e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -61,11 +61,7 @@ namespace teachos::arch::kernel // stack_overflow_test(0); memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); - - heap_test(); - - decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); - (void)descriptor_tables; + // heap_test(); context_switching::switch_to_user_mode(); } -- cgit v1.2.3 From 0c75a6ef8e47106e7fc51ca5e11eb4116e879e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 10:50:03 +0000 Subject: Improve initialize_descriptor_tables --- arch/x86_64/src/context_switching/main.cpp | 31 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5cac878..952a3b2 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -12,6 +12,10 @@ namespace teachos::arch::context_switching { namespace { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, + KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ @@ -22,30 +26,23 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { static bool initalized = false; - if (initalized) - { - descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), - interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - return tables; - } - - kernel::cpu::clear_interrupt_flag(); - segment_descriptor_table::update_global_descriptor_table_register(); - interrupt_descriptor_table::update_interrupt_descriptor_table_register(); + if (!initalized) + { + kernel::cpu::clear_interrupt_flag(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&kernel::cpu::reload_data_segment_registers, segment_selector}; - kernel::cpu::call(pointer); + segment_descriptor_table::update_global_descriptor_table_register(); + interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - segment_descriptor_table::update_task_state_segment_register(); + kernel::cpu::call(KERNEL_CODE_POINTER); + segment_descriptor_table::update_task_state_segment_register(); - kernel::cpu::set_interrupt_flag(); + kernel::cpu::set_interrupt_flag(); + initalized = true; + } descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - initalized = true; return tables; } -- cgit v1.2.3 From 3c7250a32033700944ed6f3d2174756245b22e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 13:37:55 +0000 Subject: Adjust variable name --- arch/x86_64/include/arch/kernel/cpu/segment_register.hpp | 5 ++--- arch/x86_64/src/kernel/cpu/segment_register.cpp | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp index 5c77206..6a2ca3e 100644 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -19,10 +19,9 @@ namespace teachos::arch::kernel::cpu * 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 segment_selector Data Segment that should be loaded into the registers. + * @param data_segment Value that should be loaded into the registers. */ - auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) - -> void; + 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 diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 44b4eff..891d72c 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -18,8 +18,7 @@ namespace teachos::arch::kernel::cpu } [[gnu::naked]] - auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) - -> void + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" @@ -29,7 +28,7 @@ namespace teachos::arch::kernel::cpu "mov %%rax, %%gs\n" "ret" : /* No output from call */ - : [input] "m"(segment_selector)); + : [input] "m"(data_segment)); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector -- cgit v1.2.3 From e5c62b114da77d278afe077b222b2f4feae2b94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 14:01:44 +0000 Subject: Add rax clobbered register to all segment register write calls --- arch/x86_64/src/kernel/cpu/segment_register.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 891d72c..9933e92 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -14,7 +14,10 @@ namespace teachos::arch::kernel::cpu "mov %rax, %es\n" "mov %rax, %fs\n" "mov %rax, %gs\n" - "ret"); + "ret" + : /* No output from call */ + : /* No input to call */ + : "rax"); } [[gnu::naked]] @@ -28,7 +31,8 @@ namespace teachos::arch::kernel::cpu "mov %%rax, %%gs\n" "ret" : /* No output from call */ - : [input] "m"(data_segment)); + : [input] "m"(data_segment) + : "rax"); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector @@ -90,7 +94,6 @@ namespace teachos::arch::kernel::cpu "push %[code_segment]\n" "mov %[return_function], %%rax\n" "push %%rax\n" - "iretq\n" : : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) -- cgit v1.2.3 From 4909c80b31f3198030d3e666db87cfd39ac87c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 14:07:29 +0000 Subject: Remove gnu::naked functions where not necessary. --- arch/x86_64/src/kernel/cpu/segment_register.cpp | 36 +++++++++++-------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 9933e92..b59cd1b 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -5,22 +5,19 @@ namespace teachos::arch::kernel::cpu { - [[gnu::naked]] auto reload_data_segment_registers() -> void { - asm volatile("xor %rax, %rax\n" - "mov %rax, %ss\n" - "mov %rax, %ds\n" - "mov %rax, %es\n" - "mov %rax, %fs\n" - "mov %rax, %gs\n" - "ret" - : /* No output from call */ - : /* No input to call */ + asm volatile("xor %%rax, %%rax\n" + "mov %%rax, %%ss\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + : /* no output from call */ + : /* no input to call */ : "rax"); } - [[gnu::naked]] auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { asm volatile("xor %%rax, %%rax\n" @@ -29,15 +26,14 @@ namespace teachos::arch::kernel::cpu "mov %%rax, %%es\n" "mov %%rax, %%fs\n" "mov %%rax, %%gs\n" - "ret" - : /* No output from call */ + : /* no output from call */ : [input] "m"(data_segment) : "rax"); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector { - context_switching::interrupt_descriptor_table::segment_selector current_value; + context_switching::interrupt_descriptor_table::segment_selector current_value{}; asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); return current_value; } @@ -45,11 +41,11 @@ namespace teachos::arch::kernel::cpu auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { - context_switching::interrupt_descriptor_table::segment_selector ss; - context_switching::interrupt_descriptor_table::segment_selector ds; - context_switching::interrupt_descriptor_table::segment_selector es; - context_switching::interrupt_descriptor_table::segment_selector fs; - context_switching::interrupt_descriptor_table::segment_selector gs; + context_switching::interrupt_descriptor_table::segment_selector ss{}; + context_switching::interrupt_descriptor_table::segment_selector ds{}; + context_switching::interrupt_descriptor_table::segment_selector es{}; + context_switching::interrupt_descriptor_table::segment_selector fs{}; + context_switching::interrupt_descriptor_table::segment_selector gs{}; asm volatile( "mov %%ss, %[ss_output]\n" @@ -95,7 +91,7 @@ namespace teachos::arch::kernel::cpu "mov %[return_function], %%rax\n" "push %%rax\n" "iretq\n" - : + : /* no output from call */ : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) : "rax"); } -- cgit v1.2.3 From eafe8533bb5ccbe15bd8ffbc917b38122b04a157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Apr 2025 15:21:52 +0000 Subject: Add stack frame allocator. Fix stl vector bug and create stl stack implementation --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/allocator/area_frame_allocator.hpp | 2 +- .../memory/allocator/stack_frame_allocator.hpp | 67 ++++++++ .../arch/memory/heap/global_heap_allocator.hpp | 2 +- arch/x86_64/include/arch/stl/stack.hpp | 179 +++++++++++++++++++++ arch/x86_64/include/arch/stl/vector.hpp | 82 +++++++--- arch/x86_64/src/context_switching/main.cpp | 4 +- .../src/memory/allocator/area_frame_allocator.cpp | 2 +- .../src/memory/allocator/stack_frame_allocator.cpp | 105 ++++++++++++ arch/x86_64/src/memory/main.cpp | 20 ++- 10 files changed, 433 insertions(+), 31 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp create mode 100644 arch/x86_64/include/arch/stl/stack.hpp create mode 100644 arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8f5b9bd..71b1946 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources("_memory" PRIVATE "src/memory/multiboot/elf_symbols_section.cpp" "src/memory/multiboot/reader.cpp" "src/memory/allocator/area_frame_allocator.cpp" + "src/memory/allocator/stack_frame_allocator.cpp" "src/memory/allocator/tiny_frame_allocator.cpp" "src/memory/allocator/physical_frame.cpp" "src/memory/paging/page_entry.cpp" 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 b8370db..2244613 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 @@ -55,7 +55,7 @@ namespace teachos::arch::memory::allocator 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 + 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. diff --git a/arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp new file mode 100644 index 0000000..a8e7233 --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp @@ -0,0 +1,67 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_STACK_FRAME_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_STACK_FRAME_ALLOCATOR_HPP + +#include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/multiboot/reader.hpp" +#include "arch/stl/stack.hpp" + +#include + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Uses an internal stack-like dynamic structure to keep track of the address of all avaialable physical frames + * that are available using the memory areas read from the multiboot2 information pointer and simply pushes + * deallocated frames back onto the stack. Allows for constant speed O(1) allocation and deallocation + */ + struct stack_frame_allocator + { + /** + * @brief Constructor + * + * @param mem_info Structure containg all relevant information to map and allocate memory + */ + stack_frame_allocator(multiboot::memory_information const & mem_info); + + /** + * @brief Allocate memory by finding and returning 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. + * + * @param physical_frame Previously allocated physical_frame that should be deallocated. + */ + auto deallocate_frame(physical_frame const & physical_frame) -> void; + + private: + /** + * @brief Load all initally free physical frames from the current memory area into the underlying stack data + * structure so they can simply be accessed once required. Recallling the method will load all free physical frames + * from the next free memory area until there are no memory areas left. + */ + auto load_free_physical_frames() -> void; + + /** + * @brief Find the next memory area and write it into current_area. + */ + auto choose_next_area() -> void; + + stl::stack free_frames; ///< All currently free physical frames in a LIFO (last-in, first-out) + ///< data structure. + 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 teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_STACK_FRAME_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 index dff837e..772f171 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -16,7 +16,7 @@ namespace teachos::arch::memory::heap 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 and + ///< memory }; /** diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/arch/x86_64/include/arch/stl/stack.hpp new file mode 100644 index 0000000..c78a25e --- /dev/null +++ b/arch/x86_64/include/arch/stl/stack.hpp @@ -0,0 +1,179 @@ +#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" + +#include +#include + +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. + */ + template> + struct stack + { + /** + * @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 capacity 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 stack(std::size_t capacity, T initial = T{}) + : _container(capacity, 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 + 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. + */ + 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 vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + */ + 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. + */ + 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. + */ + std::size_t size() const { 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. + */ + T & top() { 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. + */ + T const & top() const { return _container.back(); } + + /** + * @brief Appends the given element value to the end of the container. The new element is initalized as a copy of + * value. + * + * @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. + * + * @param value The value of the element to append. + */ + void push(T const & value) { _container.push_back(value); } + + /** + * @brief Appends the given element value to the end of the container. Value is moved into the new element. + * + * @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. + * + * @param value The value of the element to append. + */ + void push(T && value) { _container.push_back(std::move(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. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return T& + */ + template + auto emplace(Args &&... args) -> T & + { + _container.emplace_back(std::forward(args)...); + } + + /** + * @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. + */ + void pop() { _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. + */ + auto empty() const -> bool { return _container.empty(); } + + private: + Container _container = {}; ///< Underlying container used by the stack to actually save the data. + }; + +} // namespace teachos::arch::stl + +#endif // TEACHOS_ARCH_X86_64_STL_STACK_HPP diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index f3d41fd..e14f2c9 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -162,13 +162,9 @@ namespace teachos::arch::stl */ void push_back(T const & value) { - if (_size == _capacity) - { - reserve(_capacity * 2); - } - + increase_capacity_if_full(); _data[_size] = value; - _size++; + (void)_size++; } /** @@ -182,11 +178,7 @@ namespace teachos::arch::stl */ void push_back(T && value) { - if (_size == _capacity) - { - reserve(_capacity * 2); - } - + increase_capacity_if_full(); _data[_size] = std::move(value); _size++; } @@ -206,11 +198,7 @@ namespace teachos::arch::stl template auto emplace_back(Args &&... args) -> T & { - if (_size == _capacity) - { - reserve(_capacity * 2); - } - + increase_capacity_if_full(); _data[_size] = T{std::forward(args)...}; auto const index = _size++; return _data[index]; @@ -223,11 +211,8 @@ namespace teachos::arch::stl */ void pop_back() { - if (_size <= 0) - { - exception_handling::panic("[Vector] Attempted to pop back last element of already empty vector"); - } - _size--; + throw_if_empty(); + (void)_size--; } /** @@ -355,7 +340,11 @@ namespace teachos::arch::stl * * @return Reference to the first element. */ - T & front() { return *begin(); } + T & front() + { + throw_if_empty(); + return *begin(); + } /** * @brief Returns a reference to the first element in the container. Calling front on an empty container causes @@ -363,7 +352,11 @@ namespace teachos::arch::stl * * @return Reference to the first element. */ - T const & front() const { return *begin(); } + T const & front() const + { + throw_if_empty(); + return *begin(); + } /** * @brief Returns a reference to the last element in the container. Calling back on an empty container causes @@ -371,7 +364,11 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T & back() { return *rbegin(); } + T & back() + { + throw_if_empty(); + return *rbegin(); + } /** * @brief Returns a reference to the last element in the container. Calling back on an empty container causes @@ -379,7 +376,11 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T const & back() const { return *rbegin(); } + T const & back() const + { + throw_if_empty(); + return *rbegin(); + } /** * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without @@ -442,7 +443,38 @@ namespace teachos::arch::stl _data = temp; } + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + 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"); + } + } + + /** + * @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); + } + } + std::size_t _size = {}; ///< Amount of elements in the underlying data container std::size_t _capacity = {}; ///< Amount of space for elements in the underlying data container T * _data = {}; ///< Pointer to the first element in the underlying data container diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 952a3b2..486a09f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -21,6 +21,8 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -34,7 +36,7 @@ namespace teachos::arch::context_switching segment_descriptor_table::update_global_descriptor_table_register(); interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - kernel::cpu::call(KERNEL_CODE_POINTER); + reload_global_descriptor_table_register(); segment_descriptor_table::update_task_state_segment_register(); kernel::cpu::set_interrupt_flag(); diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index cb4fefa..a5a1b49 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::allocator { area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) - : next_free_frame(0U) + : next_free_frame() , current_area(std::nullopt) , memory_areas(mem_info.areas) , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) diff --git a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp new file mode 100644 index 0000000..0fa277a --- /dev/null +++ b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp @@ -0,0 +1,105 @@ +#include "arch/memory/allocator/stack_frame_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include +#include + +namespace teachos::arch::memory::allocator +{ + stack_frame_allocator::stack_frame_allocator(multiboot::memory_information const & mem_info) + : free_frames() + , next_free_frame() + , current_area(std::nullopt) + , memory_areas(mem_info.areas) + , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) + , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) + , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) + , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) + { + load_free_physical_frames(); + } + + auto stack_frame_allocator::load_free_physical_frames() -> void + { + choose_next_area(); + if (!current_area.has_value()) + { + return; + } + + auto const address = current_area.value().base_address + current_area.value().area_length - 1; + physical_frame const current_area_last_frame = physical_frame::containing_address(address); + + // Only try to allocate memory if current_area is not null, because + // the current_area is null if there is no more available memory. + while (next_free_frame <= current_area_last_frame) + { + if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; + } + else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; + } + else + { + // Frame is unused, increment `next_free_frame` and return it. + next_free_frame.frame_number += 1; + // TODO: Fix using heap like structure to initalize paging allocator used by heap does not work + // free_frames.push(next_free_frame); + static uint32_t count = 0U; + count++; + } + } + } + + auto stack_frame_allocator::choose_next_area() -> void + { + current_area = std::nullopt; + auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { + auto address = area.base_address + area.area_length - 1; + return physical_frame::containing_address(address) >= next_free_frame; + }); + + auto const lowest_area_with_free_frames = std::ranges::min_element( + next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); + + if (lowest_area_with_free_frames != next_area_with_free_frames.end()) + { + current_area = *lowest_area_with_free_frames; + // Update the `next_free_frame` according to the new memory area + auto const start_frame = physical_frame::containing_address(current_area.value().base_address); + if (next_free_frame < start_frame) + { + next_free_frame = start_frame; + } + } + } + + auto stack_frame_allocator::allocate_frame() -> std::optional + { + // If the underlying stack is empty that are no free frames left to allocate. + if (free_frames.empty()) + { + load_free_physical_frames(); + if (free_frames.empty()) + { + return std::nullopt; + } + } + + decltype(auto) top = free_frames.top(); + free_frames.pop(); + return top; + } + + auto stack_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void + { + free_frames.push(physical_frame); + } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a920a20..3041a75 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -4,6 +4,8 @@ #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/allocator/stack_frame_allocator.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -12,7 +14,21 @@ namespace teachos::arch::memory { namespace { - auto remap_heap(allocator::area_frame_allocator allocator, paging::active_page_table & active_table) -> void + template + auto create_frame_allocator(multiboot::memory_information const & memory_information) -> T + { + return allocator::area_frame_allocator{memory_information}; + } + + template<> + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::stack_frame_allocator + { + return allocator::stack_frame_allocator{memory_information}; + } + + template + auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); auto const end_page = @@ -36,7 +52,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - allocator::area_frame_allocator allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 9171b225c7e57db40f949ac4449b37535c46ec94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 15 Apr 2025 10:27:38 +0000 Subject: Adjust comments and readability of stack and vector implementation --- arch/x86_64/include/arch/stl/stack.hpp | 67 ++++++------ arch/x86_64/include/arch/stl/vector.hpp | 174 ++++++++++++++++++-------------- 2 files changed, 136 insertions(+), 105 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/arch/x86_64/include/arch/stl/stack.hpp index c78a25e..9ecf0ca 100644 --- a/arch/x86_64/include/arch/stl/stack.hpp +++ b/arch/x86_64/include/arch/stl/stack.hpp @@ -4,9 +4,6 @@ #include "arch/exception_handling/panic.hpp" #include "arch/stl/vector.hpp" -#include -#include - namespace teachos::arch::stl { /** @@ -14,10 +11,18 @@ namespace teachos::arch::stl * 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. */ @@ -27,11 +32,11 @@ namespace teachos::arch::stl * @brief Constructs data with the given amount of elements containg the given value or alterantively the default * constructed value. * - * @param capacity Amount of elements we want to create and set the given value for. + * @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 stack(std::size_t capacity, T initial = T{}) - : _container(capacity, initial) + explicit stack(size_type n, value_type initial = value_type{}) + : _container(n, initial) { // Nothing to do. } @@ -64,10 +69,10 @@ namespace teachos::arch::stl /** * @brief Copy constructor. * - * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * @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 vector we want to copy the data from. + * @param other Other instance of stack we want to copy the data from. */ stack(stack const & other) : _container(other) @@ -97,7 +102,7 @@ namespace teachos::arch::stl * * @return Current amount of elements. */ - std::size_t size() const { return _container.size(); } + 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 @@ -105,7 +110,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T & top() { return _container.back(); } + auto top() -> reference { return _container.back(); } /** * @brief Returns a reference to the last element in the container. Calling back on an empty container causes @@ -113,30 +118,25 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T const & top() const { return _container.back(); } + auto top() const -> const_reference { return _container.back(); } /** - * @brief Appends the given element value to the end of the container. The new element is initalized as a copy of - * value. + * @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. + * 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. */ - void push(T const & value) { _container.push_back(value); } - - /** - * @brief Appends the given element value to the end of the container. Value is moved into the new element. - * - * @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. - * - * @param value The value of the element to append. - */ - void push(T && value) { _container.push_back(std::move(value)); } + template + 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 @@ -144,24 +144,27 @@ namespace teachos::arch::stl * * 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. + * 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 T& + * @return value_type& */ template - auto emplace(Args &&... args) -> T & + auto emplace(Args &&... args) -> reference { _container.emplace_back(std::forward(args)...); } /** - * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the + * @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. */ - void pop() { _container.pop_back(); } + auto pop() -> void { _container.pop_back(); } /** * @brief Wheter there are currently any items this container or not. @@ -171,7 +174,7 @@ namespace teachos::arch::stl auto empty() const -> bool { return _container.empty(); } private: - Container _container = {}; ///< Underlying container used by the stack to actually save the data. + container_type _container = {}; ///< Underlying container used by the stack to actually save the data. }; } // namespace teachos::arch::stl diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index e14f2c9..c7d7853 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -2,9 +2,10 @@ #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 -#include namespace teachos::arch::stl { @@ -17,6 +18,13 @@ namespace teachos::arch::stl 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. */ @@ -26,15 +34,15 @@ namespace teachos::arch::stl * @brief Constructs data with the given amount of elements containg the given value or alterantively the default * constructed value. * - * @param capacity Amount of elements we want to create and set the given value for. + * @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(std::size_t capacity, T initial = T{}) - : _size(capacity) - , _capacity(capacity) - , _data(new T[_capacity]{}) + explicit vector(size_type n, value_type initial = value_type{}) + : _size(n) + , _capacity(n) + , _data(new value_type[_capacity]{}) { - std::ranges::fill(begin(), end(), initial); + std::ranges::fill(*this, initial); } /** @@ -48,9 +56,10 @@ namespace teachos::arch::stl explicit vector(InputIterator first, InputIterator last) : _size(std::distance(first, last)) , _capacity(std::distance(first, last)) - , _data(new T[_capacity]{}) + , _data(new value_type[_capacity]{}) { - std::copy(first, last, _data); + stl::container container{first, last}; + std::ranges::copy(container, _data); } /** @@ -58,12 +67,12 @@ namespace teachos::arch::stl * * @param initalizer_list List we want to copy all elements from. */ - explicit vector(std::initializer_list initalizer_list) + explicit vector(std::initializer_list initalizer_list) : _size(initalizer_list.size()) , _capacity(initalizer_list.size()) - , _data(new T[_capacity]{}) + , _data(new value_type[_capacity]{}) { - std::copy(initalizer_list.begin(), initalizer_list.end(), _data); + std::ranges::copy(initalizer_list, _data); } /** @@ -74,13 +83,13 @@ namespace teachos::arch::stl * * @param other Other instance of vector we want to copy the data from. */ - vector(vector const & other) + vector(vector const & other) : _size(other._size) , _capacity(other._capacity) { delete[] _data; - _data = new T[_capacity]{}; - std::copy(other.begin(), other.end(), _data); + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); } /** @@ -92,13 +101,13 @@ namespace teachos::arch::stl * @param other Other instance of vector we want to copy the data from. * @return Newly created copy. */ - vector & operator=(vector const & other) + vector & operator=(vector const & other) { delete[] _data; _size = other._size; _capacity = other._capacity; - _data = new T[_capacity]{}; - std::copy(other.begin(), other.end(), _data); + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); return *this; } @@ -113,7 +122,7 @@ namespace teachos::arch::stl * * @return Current amount of elements. */ - std::size_t size() const { return _size; } + 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 @@ -121,7 +130,17 @@ namespace teachos::arch::stl * * @return Current amount of space the vector has for elements. */ - std::size_t capacity() const { return _capacity; } + 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. + */ + auto operator[](size_type index) -> reference { return _data[index]; } /** * @brief Array indexing operator. Allowing to access element at the given index. @@ -131,7 +150,7 @@ namespace teachos::arch::stl * @param index Index we want to access elements at. * @return Reference to the underlying element. */ - T & operator[](std::size_t index) { return _data[index]; } + auto operator[](size_type index) const -> const_reference { return _data[index]; } /** * @brief Array indexing operator. Allowing to access element at the given index. @@ -141,46 +160,44 @@ namespace teachos::arch::stl * @param index Index we want to access elements at. * @return Reference to the underlying element. */ - T & at(std::size_t index) + auto at(size_type index) -> reference { - if (index >= _size) - { - exception_handling::panic("[Vector] Attempted to read element at invalid index"); - } + throw_if_out_of_range(index); return this->operator[](index); } /** - * @brief Appends the given element value to the end of the container. The new element is initalized as a copy of - * value. + * @brief Array indexing operator. Allowing to access element at the given index. * - * @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. + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. * - * @param value The value of the element to append. + * @param index Index we want to access elements at. + * @return Reference to the underlying element. */ - void push_back(T const & value) + auto at(size_type index) const -> const_reference { - increase_capacity_if_full(); - _data[_size] = value; - (void)_size++; + throw_if_out_of_range(index); + return this->operator[](index); } /** - * @brief Appends the given element value to the end of the container. Value is moved into the new element. + * @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. + * 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. */ - void push_back(T && value) + template + auto push_back(U && value) -> void { increase_capacity_if_full(); - _data[_size] = std::move(value); - _size++; + _data[_size] = std::forward(value); + (void)_size++; } /** @@ -189,17 +206,18 @@ namespace teachos::arch::stl * * 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. + * 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 T& + * @return value_type& */ template - auto emplace_back(Args &&... args) -> T & + auto emplace_back(Args &&... args) -> value_type & { increase_capacity_if_full(); - _data[_size] = T{std::forward(args)...}; + _data[_size] = value_type{std::forward(args)...}; auto const index = _size++; return _data[index]; } @@ -209,7 +227,7 @@ namespace teachos::arch::stl * further execution. Iterators and references to the last element are invalidated. The end() * iterator is also invalidated. */ - void pop_back() + auto pop_back() -> void { throw_if_empty(); (void)_size--; @@ -221,7 +239,7 @@ namespace teachos::arch::stl * * @return Iterator to the first element. */ - T * begin() noexcept { return _data; } + auto begin() noexcept -> pointer { return _data; } /** * @brief Returns an iterator to the first element of the vector. @@ -229,7 +247,7 @@ namespace teachos::arch::stl * * @return Iterator to the first element. */ - T const * begin() const noexcept { return _data; } + auto begin() const noexcept -> const_pointer { return _data; } /** * @brief Returns an iterator to the first element of the vector. @@ -237,7 +255,7 @@ namespace teachos::arch::stl * * @return Iterator to the first element. */ - T const * cbegin() const noexcept { return begin(); } + 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 @@ -245,7 +263,7 @@ namespace teachos::arch::stl * * @return Reverse iterator to the first element. */ - T * rbegin() noexcept { return _data + _size - 1; } + 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 @@ -253,7 +271,7 @@ namespace teachos::arch::stl * * @return Reverse iterator to the first element. */ - T const * rbegin() const noexcept { return _data + _size - 1; } + 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 @@ -261,7 +279,7 @@ namespace teachos::arch::stl * * @return Reverse iterator to the first element. */ - T const * crbegin() const noexcept { return rbegin(); } + 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 @@ -269,7 +287,7 @@ namespace teachos::arch::stl * * @return Iterator to the element following the last element. */ - T * end() noexcept { return _data + _size; } + 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 @@ -277,7 +295,7 @@ namespace teachos::arch::stl * * @return Iterator to the element following the last element. */ - T const * end() const noexcept { return _data + _size; } + 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 @@ -285,7 +303,7 @@ namespace teachos::arch::stl * * @return Iterator to the element following the last element. */ - T const * cend() const noexcept { return end(); } + 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 @@ -294,7 +312,7 @@ namespace teachos::arch::stl * * @return Reverse iterator to the element following the last element. */ - T * rend() noexcept { return _data + size - 1; } + 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 @@ -303,7 +321,7 @@ namespace teachos::arch::stl * * @return Reverse iterator to the element following the last element. */ - T const * rend() const noexcept { return _data + size - 1; } + 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 @@ -312,7 +330,7 @@ namespace teachos::arch::stl * * @return Reverse iterator to the element following the last element. */ - T const * crend() const noexcept { return rbegin(); } + 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 @@ -322,7 +340,7 @@ namespace teachos::arch::stl * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal * to the address of the first element. */ - T * data() { return _data; } + auto data() -> pointer { return _data; } /** * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range @@ -332,7 +350,7 @@ namespace teachos::arch::stl * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal * to the address of the first element. */ - T const * data() const { return _data; } + 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 @@ -340,7 +358,7 @@ namespace teachos::arch::stl * * @return Reference to the first element. */ - T & front() + auto front() -> reference { throw_if_empty(); return *begin(); @@ -352,7 +370,7 @@ namespace teachos::arch::stl * * @return Reference to the first element. */ - T const & front() const + auto front() const -> const_reference { throw_if_empty(); return *begin(); @@ -364,7 +382,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T & back() + auto back() -> reference { throw_if_empty(); return *rbegin(); @@ -376,7 +394,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - T const & back() const + auto back() const -> const_reference { throw_if_empty(); return *rbegin(); @@ -409,7 +427,7 @@ namespace teachos::arch::stl * * @param new_capacity New capacity of the vector, in number of elements */ - void reserve(std::size_t new_capacity) + auto reserve(size_type new_capacity) -> void { if (new_capacity <= _capacity) { @@ -417,8 +435,9 @@ namespace teachos::arch::stl } _capacity = new_capacity; - T * temp = new T[_capacity]{}; - std::copy(begin(), end(), temp); + value_type * temp = new value_type[_capacity]{}; + stl::container container{begin(), end()}; + std::ranges::copy(container, temp); delete[] _data; _data = temp; } @@ -429,7 +448,7 @@ namespace teachos::arch::stl * 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. */ - void shrink_to_fit() + auto shrink_to_fit() -> void { if (_size == _capacity) { @@ -437,8 +456,9 @@ namespace teachos::arch::stl } _capacity = _size; - T * temp = new T[_capacity]{}; - std::copy(begin(), end(), temp); + value_type * temp = new value_type[_capacity]{}; + stl::container container{begin(), end()}; + std::copy(container, temp); delete[] _data; _data = temp; } @@ -462,6 +482,14 @@ namespace teachos::arch::stl } } + 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 @@ -475,9 +503,9 @@ namespace teachos::arch::stl } } - std::size_t _size = {}; ///< Amount of elements in the underlying data container - std::size_t _capacity = {}; ///< Amount of space for elements in the underlying data container - T * _data = {}; ///< Pointer to the first element in the underlying data container + 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 -- cgit v1.2.3 From 8975c5fe091150245fd58a0a42a83b4f41d454e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 15 Apr 2025 13:21:34 +0000 Subject: WIP deque --- arch/x86_64/include/arch/stl/deque.hpp | 524 +++++++++++++++++++++++++++++++++ arch/x86_64/include/arch/stl/stack.hpp | 4 +- 2 files changed, 526 insertions(+), 2 deletions(-) create mode 100644 arch/x86_64/include/arch/stl/deque.hpp (limited to 'arch') diff --git a/arch/x86_64/include/arch/stl/deque.hpp b/arch/x86_64/include/arch/stl/deque.hpp new file mode 100644 index 0000000..b4a3054 --- /dev/null +++ b/arch/x86_64/include/arch/stl/deque.hpp @@ -0,0 +1,524 @@ +#ifndef TEACHOS_ARCH_X86_64_STL_DEQUE_HPP +#define TEACHOS_ARCH_X86_64_STL_DEQUE_HPP + +#include "arch/exception_handling/panic.hpp" + +#include +#include + +namespace teachos::arch::stl +{ + /** + * @brief Custom deque implementation mirroring the std::deque to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the deque instance should contain. + */ + template + struct deque + { + 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 Deque block for the linked list, either added or removed if more or less space is required. + */ + struct block + { + std::array data; ///< Data this block in the deque contains + block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. + }; + + /** + * @brief Default Constructor. + */ + deque() = 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 deque(size_type n, value_type initial = value_type{}) + : _size(n) + , _capacity(n) + , _linked_list_start() + { + std::array data{}; + std::ranges::fill_n(data, n, initial); + block block{data, nullptr}; + _linked_list_start = + █ // Taking reference to temporary, how would this be saved without causing issues later? + } + + /** + * @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 deque(InputIterator first, InputIterator last) + : _size(std::distance(first, last)) + , _capacity(std::distance(first, last)) + , _linked_list_start() + { + std::array data{}; + stl::container container{first, last}; + std::ranges::copy(container, data.begin()); + block block{data, nullptr}; + _linked_list_start = █ + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + explicit deque(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 deque we are copying from and copies all + * elements from it. + * + * @param other Other instance of deque we want to copy the data from. + */ + deque(deque 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 deque we are copying from and copies all + * elements from it. + * + * @param other Other instance of deque we want to copy the data from. + * @return Newly created copy. + */ + deque & operator=(deque const & other) + { + delete[] _data; + _size = other._size; + _capacity = other._capacity; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + return *this; + } + + /** + * @brief Destructor. + */ + ~deque() { delete[] _data; } + + /** + * @brief Amount of elements currently contained in this deque, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + auto size() const -> size_type { return _size; } + + /** + * @brief Amount of space the deque 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 deque has for elements. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. Value is moved into the new element. + * + * @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. + * + * @param value The value of the element to append. + */ + template + 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. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + 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. + */ + auto pop_back() -> void + { + throw_if_empty(); + (void)_size--; + } + + /** + * @brief Returns an iterator to the first element of the deque. + * If the deque is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + auto begin() noexcept -> pointer { return _data; } + + /** + * @brief Returns an iterator to the first element of the deque. + * If the deque is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + auto begin() const noexcept -> const_pointer { return _data; } + + /** + * @brief Returns an iterator to the first element of the deque. + * If the deque is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + auto cbegin() const noexcept -> const_pointer { return begin(); } + + /** + * @brief Returns a reverse iterator to the first element of the reversed deque. It corresponds to the last element + * of the non-reversed deque. If the deque is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + auto rbegin() noexcept -> pointer { return _data + _size - 1; } + + /** + * @brief Returns a reverse iterator to the first element of the reversed deque. It corresponds to the last element + * of the non-reversed deque. If the deque is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + auto rbegin() const noexcept -> const_pointer { return _data + _size - 1; } + + /** + * @brief Returns a reverse iterator to the first element of the reversed deque. It corresponds to the last element + * of the non-reversed deque. If the deque is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + auto crbegin() const noexcept -> const_pointer { return rbegin(); } + + /** + * @brief Returns an iterator to the element following the last element of the deque. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + auto end() noexcept -> pointer { return _data + _size; } + + /** + * @brief Returns an iterator to the element following the last element of the deque. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + auto end() const noexcept -> const_pointer { return _data + _size; } + + /** + * @brief Returns an iterator to the element following the last element of the deque. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + auto cend() const noexcept -> const_pointer { return end(); } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed deque. It + * corresponds to the element preceding the first element of the non-reversed deque. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + auto rend() noexcept -> pointer { return _data + size - 1; } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed deque. It + * corresponds to the element preceding the first element of the non-reversed deque. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + 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 deque. It + * corresponds to the element preceding the first element of the non-reversed deque. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + auto back() const -> const_reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Increase the capacity of the deque (the total number of elements that the deque 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 deque. + * + * 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 deque 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 deque by reference and appends + * elements to it should usually not call reserve() on the deque, since it does not know of the deque'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 deque, in number of elements + */ + 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. + */ + 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. + */ + 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("[Deque] Attempted to access element of currently empty deque"); + } + } + + auto throw_if_out_of_range(size_type index) const -> void + { + if (index >= _size) + { + exception_handling::panic("[Deque] 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 + block * _linked_list_start = {}; ///< Start pointer to the first element in the linked list + }; + +} // namespace teachos::arch::stl + +#endif // TEACHOS_ARCH_X86_64_STL_DEQUE_HPP diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/arch/x86_64/include/arch/stl/stack.hpp index 9ecf0ca..316aacd 100644 --- a/arch/x86_64/include/arch/stl/stack.hpp +++ b/arch/x86_64/include/arch/stl/stack.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_STL_STACK_HPP #include "arch/exception_handling/panic.hpp" -#include "arch/stl/vector.hpp" +#include "arch/stl/deque.hpp" namespace teachos::arch::stl { @@ -14,7 +14,7 @@ namespace teachos::arch::stl * @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires * access to pop_back(), push_back(), back(), size(), empty() and emplace_back() */ - template> + template> struct stack { using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. -- cgit v1.2.3 From 576a7a95b2462ec4938de9fe344657ca04b2ba34 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 17 Apr 2025 14:14:49 +0000 Subject: add syscall interrupt handler --- .../interrupt_handling/generic_interrupt_handler.hpp | 20 ++++++++++++++------ .../interrupt_descriptor_table.cpp | 7 ++++++- arch/x86_64/src/context_switching/main.cpp | 3 +++ .../interrupt_handling/generic_interrupt_handler.cpp | 7 +++++++ 4 files changed, 30 insertions(+), 7 deletions(-) (limited to 'arch') 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 index 6c1db12..309acbb 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -13,12 +13,12 @@ namespace teachos::arch::interrupt_handling */ struct [[gnu::packed]] interrupt_frame { - uint64_t error_code; ///< Error code pushed by some exceptions. - 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. + // uint64_t error_code; ///< Error code pushed by some exceptions. + 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. }; /** @@ -29,6 +29,14 @@ namespace teachos::arch::interrupt_handling [[gnu::interrupt]] auto generic_interrupt_handler(struct interrupt_frame * frame) -> void; + /** + * @brief Interrupt handler function for syscalls (INT 0x80). + * + * @param frame Pointer to the interrupt frame containing CPU state. + */ + [[gnu::interrupt]] + auto syscall_interrupt_handler(struct 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/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 80f01a8..c50ac1d 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { /// @brief Amount of currently reserved interrupt indicies. /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. - constexpr uint8_t RESERVED_INTERRUPT_COUNT = 32U; + constexpr uint16_t RESERVED_INTERRUPT_COUNT = 256U; auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { @@ -26,6 +26,11 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } + interrupt_descriptor_table.at(0x80) = { + segment_selector{3U, segment_selector::REQUEST_LEVEL_USER}, ist_offset{0U}, + idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}, + uint64_t{reinterpret_cast(interrupt_handling::syscall_interrupt_handler)}}; + return interrupt_descriptor_table; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 952a3b2..fc8790f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -49,6 +49,9 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + asm volatile("INT $0x80"); + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 4392b04..6075770 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -11,4 +11,11 @@ namespace teachos::arch::interrupt_handling (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } + + [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] + auto syscall_interrupt_handler(interrupt_frame * frame) -> void + { + (void)frame; + video::vga::text::write("A SYSCALL interrupt occurred.", video::vga::text::common_attributes::green_on_black); + } } // namespace teachos::arch::interrupt_handling -- cgit v1.2.3 From 5dc0e92a7211b44429c1a2e7efe19c146f5c4f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Apr 2025 10:52:30 +0000 Subject: Remove deque --- arch/x86_64/include/arch/stl/deque.hpp | 524 --------------------------------- arch/x86_64/include/arch/stl/stack.hpp | 4 +- arch/x86_64/src/memory/main.cpp | 10 +- 3 files changed, 3 insertions(+), 535 deletions(-) delete mode 100644 arch/x86_64/include/arch/stl/deque.hpp (limited to 'arch') diff --git a/arch/x86_64/include/arch/stl/deque.hpp b/arch/x86_64/include/arch/stl/deque.hpp deleted file mode 100644 index b4a3054..0000000 --- a/arch/x86_64/include/arch/stl/deque.hpp +++ /dev/null @@ -1,524 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_STL_DEQUE_HPP -#define TEACHOS_ARCH_X86_64_STL_DEQUE_HPP - -#include "arch/exception_handling/panic.hpp" - -#include -#include - -namespace teachos::arch::stl -{ - /** - * @brief Custom deque implementation mirroring the std::deque to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the deque instance should contain. - */ - template - struct deque - { - 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 Deque block for the linked list, either added or removed if more or less space is required. - */ - struct block - { - std::array data; ///< Data this block in the deque contains - block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. - }; - - /** - * @brief Default Constructor. - */ - deque() = 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 deque(size_type n, value_type initial = value_type{}) - : _size(n) - , _capacity(n) - , _linked_list_start() - { - std::array data{}; - std::ranges::fill_n(data, n, initial); - block block{data, nullptr}; - _linked_list_start = - █ // Taking reference to temporary, how would this be saved without causing issues later? - } - - /** - * @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 deque(InputIterator first, InputIterator last) - : _size(std::distance(first, last)) - , _capacity(std::distance(first, last)) - , _linked_list_start() - { - std::array data{}; - stl::container container{first, last}; - std::ranges::copy(container, data.begin()); - block block{data, nullptr}; - _linked_list_start = █ - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - explicit deque(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 deque we are copying from and copies all - * elements from it. - * - * @param other Other instance of deque we want to copy the data from. - */ - deque(deque 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 deque we are copying from and copies all - * elements from it. - * - * @param other Other instance of deque we want to copy the data from. - * @return Newly created copy. - */ - deque & operator=(deque const & other) - { - delete[] _data; - _size = other._size; - _capacity = other._capacity; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - return *this; - } - - /** - * @brief Destructor. - */ - ~deque() { delete[] _data; } - - /** - * @brief Amount of elements currently contained in this deque, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - auto size() const -> size_type { return _size; } - - /** - * @brief Amount of space the deque 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 deque has for elements. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. Value is moved into the new element. - * - * @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. - * - * @param value The value of the element to append. - */ - template - 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. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - 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. - */ - auto pop_back() -> void - { - throw_if_empty(); - (void)_size--; - } - - /** - * @brief Returns an iterator to the first element of the deque. - * If the deque is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - auto begin() noexcept -> pointer { return _data; } - - /** - * @brief Returns an iterator to the first element of the deque. - * If the deque is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - auto begin() const noexcept -> const_pointer { return _data; } - - /** - * @brief Returns an iterator to the first element of the deque. - * If the deque is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - auto cbegin() const noexcept -> const_pointer { return begin(); } - - /** - * @brief Returns a reverse iterator to the first element of the reversed deque. It corresponds to the last element - * of the non-reversed deque. If the deque is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - auto rbegin() noexcept -> pointer { return _data + _size - 1; } - - /** - * @brief Returns a reverse iterator to the first element of the reversed deque. It corresponds to the last element - * of the non-reversed deque. If the deque is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - auto rbegin() const noexcept -> const_pointer { return _data + _size - 1; } - - /** - * @brief Returns a reverse iterator to the first element of the reversed deque. It corresponds to the last element - * of the non-reversed deque. If the deque is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - auto crbegin() const noexcept -> const_pointer { return rbegin(); } - - /** - * @brief Returns an iterator to the element following the last element of the deque. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - auto end() noexcept -> pointer { return _data + _size; } - - /** - * @brief Returns an iterator to the element following the last element of the deque. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - auto end() const noexcept -> const_pointer { return _data + _size; } - - /** - * @brief Returns an iterator to the element following the last element of the deque. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - auto cend() const noexcept -> const_pointer { return end(); } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed deque. It - * corresponds to the element preceding the first element of the non-reversed deque. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - auto rend() noexcept -> pointer { return _data + size - 1; } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed deque. It - * corresponds to the element preceding the first element of the non-reversed deque. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - 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 deque. It - * corresponds to the element preceding the first element of the non-reversed deque. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - auto back() const -> const_reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Increase the capacity of the deque (the total number of elements that the deque 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 deque. - * - * 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 deque 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 deque by reference and appends - * elements to it should usually not call reserve() on the deque, since it does not know of the deque'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 deque, in number of elements - */ - 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. - */ - 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. - */ - 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("[Deque] Attempted to access element of currently empty deque"); - } - } - - auto throw_if_out_of_range(size_type index) const -> void - { - if (index >= _size) - { - exception_handling::panic("[Deque] 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 - block * _linked_list_start = {}; ///< Start pointer to the first element in the linked list - }; - -} // namespace teachos::arch::stl - -#endif // TEACHOS_ARCH_X86_64_STL_DEQUE_HPP diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/arch/x86_64/include/arch/stl/stack.hpp index 316aacd..9ecf0ca 100644 --- a/arch/x86_64/include/arch/stl/stack.hpp +++ b/arch/x86_64/include/arch/stl/stack.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_STL_STACK_HPP #include "arch/exception_handling/panic.hpp" -#include "arch/stl/deque.hpp" +#include "arch/stl/vector.hpp" namespace teachos::arch::stl { @@ -14,7 +14,7 @@ namespace teachos::arch::stl * @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires * access to pop_back(), push_back(), back(), size(), empty() and emplace_back() */ - template> + template> struct stack { using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 3041a75..bd094e0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -5,7 +5,6 @@ #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/allocator/stack_frame_allocator.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -20,13 +19,6 @@ namespace teachos::arch::memory return allocator::area_frame_allocator{memory_information}; } - template<> - auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::stack_frame_allocator - { - return allocator::stack_frame_allocator{memory_information}; - } - template auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { @@ -52,7 +44,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 0986058bb9ca5b4afd7c578c815dc3a4c08808a9 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Mon, 21 Apr 2025 08:18:41 +0000 Subject: WIP syscall --- .../interrupt_descriptor_table.cpp | 4 ++-- arch/x86_64/src/context_switching/main.cpp | 9 ++++++++- .../generic_interrupt_handler.cpp | 22 +++++++++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index c50ac1d..c041198 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -27,8 +27,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table } interrupt_descriptor_table.at(0x80) = { - segment_selector{3U, segment_selector::REQUEST_LEVEL_USER}, ist_offset{0U}, - idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}, + segment_selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}, ist_offset{0U}, + idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::TRAP_GATE | idt_flags::PRESENT}, uint64_t{reinterpret_cast(interrupt_handling::syscall_interrupt_handler)}}; return interrupt_descriptor_table; diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7be286a..faaf831 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -52,7 +52,14 @@ namespace teachos::arch::context_switching { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - asm volatile("INT $0x80"); + // TODO/INFO: + // https://stackoverflow.com/questions/46022184/osdev-syscall-sysret-and-sysenter-sysexit-instructions-enabling + // https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall-in-32-bit-code-on-linux + // + // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! + + // asm volatile("INT $0x80"); + asm volatile("SYSCALL"); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 6075770..7afd87d 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -15,7 +15,27 @@ namespace teachos::arch::interrupt_handling [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto syscall_interrupt_handler(interrupt_frame * frame) -> void { + // RDI, RSI, RDX, RCX, R8, R9 + // RDI -> SYSCALL number + // Others are arguments + + // TODO: The registers are not available here. We need to set them up on the stack + // and access them via argument. + + uint64_t syscall_number{}; + asm volatile("mov %%rdi, %0" : "=r"(syscall_number)); + + // Handle system call based on the number + switch (syscall_number) + { + case 1: + video::vga::text::write("SYSCALL 1.", video::vga::text::common_attributes::green_on_black); + break; + default: + // Handle unknown syscall + break; + } + (void)frame; - video::vga::text::write("A SYSCALL interrupt occurred.", video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::interrupt_handling -- cgit v1.2.3 From 5f149faeb9d41bb56733075b0e56908b3731d38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 09:32:59 +0000 Subject: Move gnu function attributes to header file --- .../include/arch/interrupt_handling/generic_interrupt_handler.hpp | 4 ++-- arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp | 3 --- arch/x86_64/src/memory/heap/bump_allocator.cpp | 4 +++- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'arch') 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 index 309acbb..9530a77 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -26,7 +26,7 @@ namespace teachos::arch::interrupt_handling * * @param frame Pointer to the interrupt frame containing CPU state. */ - [[gnu::interrupt]] + [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto generic_interrupt_handler(struct interrupt_frame * frame) -> void; /** @@ -34,7 +34,7 @@ namespace teachos::arch::interrupt_handling * * @param frame Pointer to the interrupt frame containing CPU state. */ - [[gnu::interrupt]] + [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto syscall_interrupt_handler(struct interrupt_frame * frame) -> void; } // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 7afd87d..60fb50c 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -4,15 +4,12 @@ namespace teachos::arch::interrupt_handling { - - [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto generic_interrupt_handler(interrupt_frame * frame) -> void { (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } - [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto syscall_interrupt_handler(interrupt_frame * frame) -> void { // RDI, RSI, RDX, RCX, R8, R9 diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index df95346..525f45c 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -24,11 +24,13 @@ namespace teachos::arch::memory::heap auto bump_allocator::allocate(std::size_t size) -> void * { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time // causing the value to differ and the calculation to have to be redone. for (;;) { - auto alloc_start = next.load(std::memory_order::relaxed); auto const alloc_end = saturating_add(alloc_start, size); arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another -- cgit v1.2.3 From c865eff02ae1978b4f665432d853374d1ffacecf Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 10:21:29 +0000 Subject: create trampoline for syscall --- arch/x86_64/include/arch/boot/pointers.hpp | 2 ++ arch/x86_64/src/boot/boot.s | 25 +++++++++++++++++++++++++ arch/x86_64/src/context_switching/main.cpp | 4 +++- 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index fe9c657..d9a7ab7 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -10,6 +10,8 @@ namespace teachos::arch::boot */ extern "C" size_t const multiboot_information_pointer; + extern "C" void syscall_trampoline(); + } // namespace teachos::arch::boot #endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..24b38ca 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,6 +352,31 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +syscall_target: + iretq + +.global syscall_trampoline +syscall_trampoline: + /* Write target function pointer in IA32_LSTAR MSR */ + mov $0xC0000082, %ecx /* IA32_LSTAR MSR */ + lea [syscall_target], %rax + lea [syscall_target], %rdx + shr $32, %rdx + wrmsr + + /* Write ... in IA32_LSTAR MSR */ + mov $0xC0000084, %ecx /* IA32_FMASK MSR */ + mov $0x0, %rax /* ... lower 32 bits */ + mov $0x0, %rdx /* ... upper 32 bits */ + wrmsr + + /* Write Segment selector in IA32_STAR MSR */ + mov $0xC0000081, %ecx /* IA32_STAR MSR */ + mov $0x10, %rax /* SS lower 32 bits */ + mov $0x0, %rdx /* SS upper 32 bits */ + wrmsr + + _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index faaf831..c949488 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,5 +1,6 @@ #include "arch/context_switching/main.hpp" +#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -59,7 +60,8 @@ namespace teachos::arch::context_switching // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! // asm volatile("INT $0x80"); - asm volatile("SYSCALL"); + // asm volatile("SYSCALL"); + boot::syscall_trampoline(); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 7261c64bb236a313ed8846a9c9dbded6890a9e98 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 11:20:02 +0000 Subject: wip implement syscall in cpp --- arch/x86_64/CMakeLists.txt | 1 + arch/x86_64/include/arch/boot/pointers.hpp | 2 - .../x86_64/include/arch/context_switching/main.hpp | 2 + .../arch/context_switching/syscall_handler.hpp | 8 ++++ arch/x86_64/src/boot/boot.s | 25 ------------- arch/x86_64/src/context_switching/main.cpp | 43 +++++++++++++++++----- .../src/context_switching/syscall_handler.cpp | 20 ++++++++++ arch/x86_64/src/kernel/main.cpp | 1 + 8 files changed, 66 insertions(+), 36 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/syscall_handler.hpp create mode 100644 arch/x86_64/src/context_switching/syscall_handler.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 71b1946..d5fb913 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -105,6 +105,7 @@ target_sources("_context" PRIVATE "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp" "src/context_switching/interrupt_descriptor_table/ist_offset.cpp" "src/context_switching/interrupt_descriptor_table/segment_selector.cpp" + "src/context_switching/syscall_handler.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index d9a7ab7..fe9c657 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -10,8 +10,6 @@ namespace teachos::arch::boot */ extern "C" size_t const multiboot_information_pointer; - extern "C" void syscall_trampoline(); - } // namespace teachos::arch::boot #endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/include/arch/context_switching/main.hpp index f8477ea..5537174 100644 --- a/arch/x86_64/include/arch/context_switching/main.hpp +++ b/arch/x86_64/include/arch/context_switching/main.hpp @@ -46,6 +46,8 @@ namespace teachos::arch::context_switching auto switch_context(interrupt_descriptor_table::segment_selector data_segment, interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void; + auto setup_syscall() -> 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/syscall_handler.hpp b/arch/x86_64/include/arch/context_switching/syscall_handler.hpp new file mode 100644 index 0000000..8583051 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/syscall_handler.hpp @@ -0,0 +1,8 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_HANDLER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_HANDLER_HPP + +namespace teachos::arch::context_switching +{ + auto syscall_handler() -> void; +} +#endif \ No newline at end of file diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 24b38ca..7932045 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,31 +352,6 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -syscall_target: - iretq - -.global syscall_trampoline -syscall_trampoline: - /* Write target function pointer in IA32_LSTAR MSR */ - mov $0xC0000082, %ecx /* IA32_LSTAR MSR */ - lea [syscall_target], %rax - lea [syscall_target], %rdx - shr $32, %rdx - wrmsr - - /* Write ... in IA32_LSTAR MSR */ - mov $0xC0000084, %ecx /* IA32_FMASK MSR */ - mov $0x0, %rax /* ... lower 32 bits */ - mov $0x0, %rdx /* ... upper 32 bits */ - wrmsr - - /* Write Segment selector in IA32_STAR MSR */ - mov $0xC0000081, %ecx /* IA32_STAR MSR */ - mov $0x10, %rax /* SS lower 32 bits */ - mov $0x0, %rdx /* SS upper 32 bits */ - wrmsr - - _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c949488..85cefe5 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,6 +1,7 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall_handler.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -53,15 +54,7 @@ namespace teachos::arch::context_switching { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - // TODO/INFO: - // https://stackoverflow.com/questions/46022184/osdev-syscall-sysret-and-sysenter-sysexit-instructions-enabling - // https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall-in-32-bit-code-on-linux - // - // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! - - // asm volatile("INT $0x80"); - // asm volatile("SYSCALL"); - boot::syscall_trampoline(); + asm volatile("SYSCALL"); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } @@ -79,4 +72,36 @@ namespace teachos::arch::context_switching kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } + auto setup_syscall() -> void + { + uint64_t handler = reinterpret_cast(syscall_handler); + asm volatile( + /* Write syscall_handler pointer in IA32_LSTAR MSR */ + "mov $0xC0000082, %%ecx\n" /* IA32_LSTAR MSR */ + "mov %[syscall_handler], %%rax" + "mov %[syscall_handler], %%rdx" + "shr $32, %%rdx\n" + "wrmsr\n" + + /* Write RFLAGS Mask in IA32_LSTAR MSR */ + "mov $0xC0000084, %%ecx\n" /* IA32_FMASK MSR */ + "mov $0x0, %%rax\n" /* RFLAGS Mask lower 32 bits */ + "mov $0x0, %%rdx\n" /* RFLAGS Mask upper 32 bits */ + "wrmsr\n" + + /* Write kernel code segment offset in IA32_STAR MSR */ + "mov $0xC0000081, %%ecx\n" /* IA32_STAR MSR */ + "mov $0x10, %%rax\n" /* kernel code segment offset lower 32 bits */ + "mov $0x0, %%rdx\n" /* kernel code segment offset upper 32 bits */ + "wrmsr\n" + + /* Set SCE bit in MSR_EFER (enabling syscall instruction)*/ + "mov $0xC0000080, %%ecx\n" + "rdmsr\n" + "or $0x1, %%eax\n" + "wrmsr" + : /* no output from call */ + : [syscall_handler] "r"(handler)); + } + } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall_handler.cpp new file mode 100644 index 0000000..1bc4ef9 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall_handler.cpp @@ -0,0 +1,20 @@ +#include "arch/context_switching/syscall_handler.hpp" + +#include + +namespace teachos::arch::context_switching +{ + [[gnu::naked]] + auto syscall_handler() -> void + { + uint64_t dummy{}; + switch (dummy) + { + case 0: + break; + default: + break; + } + asm volatile("SYSRET"); + } +} // namespace teachos::arch::context_switching \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 05c879e..e737d44 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,6 +63,7 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); // heap_test(); + context_switching::setup_syscall(); context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 187eba4eca3ea46d8c26419168e525242338dae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 13:18:49 +0000 Subject: Simplify syscall setup --- .../arch/context_switching/syscall_handler.hpp | 1 + .../include/arch/kernel/cpu/segment_register.hpp | 1 + arch/x86_64/src/context_switching/main.cpp | 40 +++++++--------------- .../src/context_switching/syscall_handler.cpp | 1 - arch/x86_64/src/kernel/cpu/segment_register.cpp | 1 - 5 files changed, 14 insertions(+), 30 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/syscall_handler.hpp b/arch/x86_64/include/arch/context_switching/syscall_handler.hpp index 8583051..5a46924 100644 --- a/arch/x86_64/include/arch/context_switching/syscall_handler.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall_handler.hpp @@ -3,6 +3,7 @@ namespace teachos::arch::context_switching { + [[gnu::naked]] auto syscall_handler() -> void; } #endif \ 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 index 6a2ca3e..36ada23 100644 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -86,6 +86,7 @@ namespace teachos::arch::kernel::cpu * @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; diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 85cefe5..155d150 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -6,6 +6,7 @@ #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/msr.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/video/vga/text.hpp" @@ -14,6 +15,10 @@ namespace teachos::arch::context_switching { namespace { + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, @@ -74,34 +79,13 @@ namespace teachos::arch::context_switching auto setup_syscall() -> void { - uint64_t handler = reinterpret_cast(syscall_handler); - asm volatile( - /* Write syscall_handler pointer in IA32_LSTAR MSR */ - "mov $0xC0000082, %%ecx\n" /* IA32_LSTAR MSR */ - "mov %[syscall_handler], %%rax" - "mov %[syscall_handler], %%rdx" - "shr $32, %%rdx\n" - "wrmsr\n" - - /* Write RFLAGS Mask in IA32_LSTAR MSR */ - "mov $0xC0000084, %%ecx\n" /* IA32_FMASK MSR */ - "mov $0x0, %%rax\n" /* RFLAGS Mask lower 32 bits */ - "mov $0x0, %%rdx\n" /* RFLAGS Mask upper 32 bits */ - "wrmsr\n" - - /* Write kernel code segment offset in IA32_STAR MSR */ - "mov $0xC0000081, %%ecx\n" /* IA32_STAR MSR */ - "mov $0x10, %%rax\n" /* kernel code segment offset lower 32 bits */ - "mov $0x0, %%rdx\n" /* kernel code segment offset upper 32 bits */ - "wrmsr\n" - - /* Set SCE bit in MSR_EFER (enabling syscall instruction)*/ - "mov $0xC0000080, %%ecx\n" - "rdmsr\n" - "or $0x1, %%eax\n" - "wrmsr" - : /* no output from call */ - : [syscall_handler] "r"(handler)); + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + uint64_t const segment_selector = *reinterpret_cast(&KERNEL_CODE_SEGMENT_SELECTOR); + + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, segment_selector); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall_handler.cpp index 1bc4ef9..283d297 100644 --- a/arch/x86_64/src/context_switching/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall_handler.cpp @@ -4,7 +4,6 @@ namespace teachos::arch::context_switching { - [[gnu::naked]] auto syscall_handler() -> void { uint64_t dummy{}; diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index b59cd1b..b08c9c4 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -78,7 +78,6 @@ namespace teachos::arch::kernel::cpu validate_code_segment_register(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 -- cgit v1.2.3 From 13dd2bd5a88ec7efeadf8586778f2c5a26d8cd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 14:07:33 +0000 Subject: Move not public methods into anonymous namespace --- arch/x86_64/CMakeLists.txt | 1 - .../segment_selector.hpp | 7 +++ .../x86_64/include/arch/context_switching/main.hpp | 2 - .../arch/context_switching/syscall_handler.hpp | 9 ---- arch/x86_64/src/context_switching/main.cpp | 59 ++++++++++++++-------- .../src/context_switching/syscall_handler.cpp | 19 ------- arch/x86_64/src/kernel/cpu/msr.cpp | 2 +- arch/x86_64/src/kernel/main.cpp | 1 - 8 files changed, 46 insertions(+), 54 deletions(-) delete mode 100644 arch/x86_64/include/arch/context_switching/syscall_handler.hpp delete mode 100644 arch/x86_64/src/context_switching/syscall_handler.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index d5fb913..71b1946 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -105,7 +105,6 @@ target_sources("_context" PRIVATE "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp" "src/context_switching/interrupt_descriptor_table/ist_offset.cpp" "src/context_switching/interrupt_descriptor_table/segment_selector.cpp" - "src/context_switching/syscall_handler.cpp" ) #[============================================================================[ 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 index e8854f9..7bfb563 100644 --- 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 @@ -82,6 +82,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table */ auto operator|=(std::bitset<3U> other) -> void; + /** + * @brief Combines all bits in the underlying data in the correct order to return a raw value containing all bits. + * + * @return Underlying value combined into it's full size. + */ + operator uint16_t() const { return static_cast(_flags) | (static_cast(_index) << 3U); } + private: uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. uint16_t _index : 13 = diff --git a/arch/x86_64/include/arch/context_switching/main.hpp b/arch/x86_64/include/arch/context_switching/main.hpp index 5537174..f8477ea 100644 --- a/arch/x86_64/include/arch/context_switching/main.hpp +++ b/arch/x86_64/include/arch/context_switching/main.hpp @@ -46,8 +46,6 @@ namespace teachos::arch::context_switching auto switch_context(interrupt_descriptor_table::segment_selector data_segment, interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void; - auto setup_syscall() -> 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/syscall_handler.hpp b/arch/x86_64/include/arch/context_switching/syscall_handler.hpp deleted file mode 100644 index 5a46924..0000000 --- a/arch/x86_64/include/arch/context_switching/syscall_handler.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_HANDLER_HPP - -namespace teachos::arch::context_switching -{ - [[gnu::naked]] - auto syscall_handler() -> void; -} -#endif \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 155d150..f73cb19 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,7 +1,6 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall_handler.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -30,6 +29,43 @@ namespace teachos::arch::context_switching auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + auto user_mode_main() -> void + { + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + + asm volatile("syscall"); + + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRET!", + video::vga::text::common_attributes::green_on_black); + } + + auto syscall_handler() -> void + { + uint64_t dummy{}; + switch (dummy) + { + case 0: + break; + default: + break; + } + + asm volatile("sysretq"); + } + + auto enable_systemcall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } + } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -55,17 +91,9 @@ namespace teachos::arch::context_switching return tables; } - auto user_mode_main() -> void - { - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - - asm volatile("SYSCALL"); - - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); - } - auto switch_to_user_mode() -> void { + enable_systemcall(); switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); } @@ -77,15 +105,4 @@ namespace teachos::arch::context_switching kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } - auto setup_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - uint64_t const segment_selector = *reinterpret_cast(&KERNEL_CODE_SEGMENT_SELECTOR); - - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, segment_selector); - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall_handler.cpp deleted file mode 100644 index 283d297..0000000 --- a/arch/x86_64/src/context_switching/syscall_handler.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "arch/context_switching/syscall_handler.hpp" - -#include - -namespace teachos::arch::context_switching -{ - auto syscall_handler() -> void - { - uint64_t dummy{}; - switch (dummy) - { - case 0: - break; - default: - break; - } - asm volatile("SYSRET"); - } -} // namespace teachos::arch::context_switching \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp index 6249f8f..9c474a1 100644 --- a/arch/x86_64/src/kernel/cpu/msr.cpp +++ b/arch/x86_64/src/kernel/cpu/msr.cpp @@ -16,7 +16,7 @@ namespace teachos::arch::kernel::cpu auto write_msr(uint32_t msr, uint64_t value) -> void { - uint32_t low = value & 0xFFFFFFFF; + uint32_t low = value; uint32_t high = value >> 32; asm volatile("wrmsr" : /* no output from call */ diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index e737d44..05c879e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,7 +63,6 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); // heap_test(); - context_switching::setup_syscall(); context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From a8a8e09ed39268839ca838c44489bb1352892fef Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 14:11:43 +0000 Subject: merge --- arch/x86_64/src/context_switching/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index f73cb19..287ced4 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -104,5 +104,4 @@ namespace teachos::arch::context_switching kernel::cpu::set_data_segment_registers(data_segment); kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } - } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 7c5a40a0de0c5e3ce0a51aa5414c4a433190c60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 14:17:19 +0000 Subject: Add validate methods. For WIP systemcall --- arch/x86_64/src/context_switching/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 287ced4..bd48e18 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -20,6 +20,8 @@ namespace teachos::arch::context_switching constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + constexpr interrupt_descriptor_table::segment_selector KERNEL_DATA_SEGMENT_SELECTOR{ + 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ @@ -45,6 +47,8 @@ namespace teachos::arch::context_switching auto syscall_handler() -> void { + kernel::cpu::validate_segment_registers(KERNEL_CODE_SEGMENT_SELECTOR, KERNEL_DATA_SEGMENT_SELECTOR); + uint64_t dummy{}; switch (dummy) { -- cgit v1.2.3 From 95c299db969b29eb4a4742ff7715adecfe138bd5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 14:43:31 +0000 Subject: test different values --- arch/x86_64/src/context_switching/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 287ced4..4e13b1c 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -62,7 +62,16 @@ namespace teachos::arch::context_switching uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // Your 64-bit kernel code segment selector + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR + 0x3; // User mode code segment selector (RPL=3) + + uint64_t star_value = (user_cs << 48) | (kernel_cs << 32); + + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); + + // kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -- cgit v1.2.3 From adb66c18b9e6ca0f65934f453afda1c5f9fe145f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 15:14:04 +0000 Subject: wip enable syscall --- arch/x86_64/src/context_switching/main.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 33af765..21299da 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -33,22 +33,16 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); asm volatile("syscall"); - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - - video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRET!", + video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } auto syscall_handler() -> void { - kernel::cpu::validate_segment_registers(KERNEL_CODE_SEGMENT_SELECTOR, KERNEL_DATA_SEGMENT_SELECTOR); - uint64_t dummy{}; switch (dummy) { @@ -65,17 +59,19 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // Your 64-bit kernel code segment selector - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR + 0x3; // User mode code segment selector (RPL=3) - - uint64_t star_value = (user_cs << 48) | (kernel_cs << 32); - + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall + + // @MTO: This produces following values: + // After SYSCALL: CS = 0x10, SS = 0x18 + // After SYSRETQ: CS = 0x43, SS = 0x3b + // + // We probably need to modify our GDT, because the cs+8 = ss is an issue we cannot solve. + // Also, CS = 0x43 is weird. I expected it to be 0x33. + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR; + uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); - // kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -- cgit v1.2.3 From 151b699058d994c0aee18cc17fe56aecc15ea336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Apr 2025 14:45:54 +0000 Subject: Remove duplicate struct --- .../include/arch/interrupt_handling/generic_interrupt_handler.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') 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 index 9530a77..866d15d 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -27,7 +27,7 @@ namespace teachos::arch::interrupt_handling * @param frame Pointer to the interrupt frame containing CPU state. */ [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] - auto generic_interrupt_handler(struct interrupt_frame * frame) -> void; + auto generic_interrupt_handler(interrupt_frame * frame) -> void; /** * @brief Interrupt handler function for syscalls (INT 0x80). @@ -35,7 +35,7 @@ namespace teachos::arch::interrupt_handling * @param frame Pointer to the interrupt frame containing CPU state. */ [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] - auto syscall_interrupt_handler(struct interrupt_frame * frame) -> void; + auto syscall_interrupt_handler(interrupt_frame * frame) -> void; } // namespace teachos::arch::interrupt_handling -- cgit v1.2.3 From ecdfbc3e1458923f619f0d4b8a841a6e96a6678a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Apr 2025 15:01:44 +0000 Subject: Start adding parameters to syscall --- arch/x86_64/src/context_switching/main.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 21299da..2a2a188 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -35,6 +35,11 @@ namespace teachos::arch::context_switching { video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + uint64_t new_value = 60U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); asm volatile("syscall"); video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", @@ -43,10 +48,16 @@ namespace teachos::arch::context_switching auto syscall_handler() -> void { - uint64_t dummy{}; - switch (dummy) + uint64_t syscall_number{}; + asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + + switch (syscall_number) { - case 0: + case 1: + // Write VGA + break; + case 60U: + // Exit break; default: break; -- cgit v1.2.3 From f0627d43909a8c19f41f3699757918c0185b5f1a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 30 Apr 2025 12:53:44 +0000 Subject: fix cs register after sysretq --- arch/x86_64/src/context_switching/main.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 2a2a188..8d1c019 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -42,7 +42,7 @@ namespace teachos::arch::context_switching : "memory"); asm volatile("syscall"); - video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } @@ -70,16 +70,12 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall - - // @MTO: This produces following values: - // After SYSCALL: CS = 0x10, SS = 0x18 - // After SYSRETQ: CS = 0x43, SS = 0x3b - // - // We probably need to modify our GDT, because the cs+8 = ss is an issue we cannot solve. - // Also, CS = 0x43 is weird. I expected it to be 0x33. + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall. + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR; + // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the + // cs register (See https://www.felixcloutier.com/x86/sysret). + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR - 0x10; uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); -- cgit v1.2.3 From 5eb8d63a6ece530cb1d56217a046553b4b96245d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 30 Apr 2025 14:50:34 +0000 Subject: Note linux calling contract for implementation --- arch/x86_64/src/context_switching/main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 8d1c019..7db9583 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -35,6 +35,16 @@ namespace teachos::arch::context_switching { video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + // RFLAGS is saved into R11, RIP of the next instruction into RCX + // Required for SYSRETURN to know where to return too. + // Additional state needs to be saved by calling convention: + + // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) + // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 + // Not used registers: RBX, RSP, R12, R13, R14 + + // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: + // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html uint64_t new_value = 60U; asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -70,7 +80,7 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall. + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the -- cgit v1.2.3 From 7c045d8ded72017ff11fd4b9b02148987b944caf Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 1 May 2025 12:25:40 +0000 Subject: WIP experiment with converting GDT to 8-Byte entries --- arch/x86_64/CMakeLists.txt | 2 + .../segment_selector.hpp | 8 +-- .../global_descriptor_table.hpp | 6 +- .../global_descriptor_table_pointer.hpp | 18 ++++-- .../segment_descriptor.hpp | 12 ++++ .../segment_descriptor_base.hpp | 34 +++++++++++ .../segment_descriptor_extension.hpp | 31 +++++++++++ arch/x86_64/src/context_switching/main.cpp | 24 +++++--- .../global_descriptor_table.cpp | 65 ++++++++++++---------- .../global_descriptor_table_pointer.cpp | 3 +- .../segment_descriptor.cpp | 11 ++++ .../segment_descriptor_base.cpp | 13 +++++ .../segment_descriptor_extension.cpp | 10 ++++ arch/x86_64/src/kernel/cpu/call.cpp | 3 +- 14 files changed, 188 insertions(+), 52 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp create mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 71b1946..58afdb5 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -98,6 +98,8 @@ target_sources("_context" PRIVATE "src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp" "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor.cpp" + "src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp" + "src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp" "src/context_switching/main.cpp" "src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp" "src/context_switching/interrupt_descriptor_table/idt_flags.cpp" 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 index 7bfb563..8748448 100644 --- 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 @@ -44,17 +44,13 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table * @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. Because it only - * multiplies by 8, but we are using long mode the constructor additionally multiplies the given value by two. This - * is done because 64-bit segment descriptor are twice as big in size. If we wouldn't multiply by two, index 1 would - * result in the middle between the second part of the null entry and the first part of the code kernel segment and - * therefore be invalid. + * 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 * 2U) + , _index(index) { // Nothing to do. } 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 index bd69a46..84a24a2 100644 --- 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 @@ -12,7 +12,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table * * @return Reference to the created global_descriptor_table. */ - auto get_or_create_global_descriptor_table() -> 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 @@ -21,13 +21,13 @@ namespace teachos::arch::context_switching::segment_descriptor_table * @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_global_descriptor_table_register() -> void; + 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_global_descriptor_table_register() and a far jump has been + * @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_task_state_segment_register() -> void; 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 index 6fac2a0..c54647d 100644 --- 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 @@ -1,14 +1,24 @@ #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/context_switching/segment_descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" #include "arch/stl/vector.hpp" #include namespace teachos::arch::context_switching::segment_descriptor_table { - using global_descriptor_table = stl::vector; + struct __attribute__((packed, aligned(8))) global_descriptor_table + { + segment_descriptor_base null; + segment_descriptor_base kernel_code; + segment_descriptor_base kernel_data; + segment_descriptor_base user_code; + segment_descriptor_base user_data; + segment_descriptor_base tss_low; + segment_descriptor_extension tss_high; + }; /** * @brief Represents a pointer to the Global Descriptor Table (GDT). @@ -26,7 +36,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Constructor. */ - global_descriptor_table_pointer(uint16_t table_length, segment_descriptor * address); + global_descriptor_table_pointer(uint16_t table_length, seg_desc * address); /** * @brief Defaulted three-way comparsion operator. @@ -35,7 +45,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table private: uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - segment_descriptor * address = {}; ///< Non-owning pointer to the GDT base address. + seg_desc * address = {}; ///< Non-owning pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp index 7fe4ecb..ccd604d 100644 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp @@ -10,6 +10,12 @@ namespace teachos::arch::context_switching::segment_descriptor_table __extension__ typedef __int128 int128_t; __extension__ typedef unsigned __int128 uint128_t; + struct seg_desc + { + private: + uint64_t : 64; ///< Makes sure the struct is 8-Bytes big + }; + /** * @brief Defines helper function for all states and the actual data the segment descriptor can have. */ @@ -44,6 +50,12 @@ namespace teachos::arch::context_switching::segment_descriptor_table */ segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit); + auto get_limit_1() -> uint16_t; + auto get_base_1() -> uint32_t; + auto get_access() -> access_byte; + auto get_flag() -> gdt_flags; + auto get_base_2() -> uint64_t; + /** * @brief Calculates the underlying segment type that this segement descriptor is describing. */ 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 new file mode 100644 index 0000000..18c9da1 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp @@ -0,0 +1,34 @@ +#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.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 : seg_desc + { + /** + * @brief Default Constructor. + */ + segment_descriptor_base() = default; + + /** + * @brief Constructor. + */ + segment_descriptor_base(segment_descriptor segment_descriptor); + + private: + 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) + }; +} // 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 new file mode 100644 index 0000000..0b724f2 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp @@ -0,0 +1,31 @@ +#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.hpp" + +#include + +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_extension : seg_desc + { + /** + * @brief Default Constructor. + */ + segment_descriptor_extension() = default; + + /** + * @brief Constructor. + */ + segment_descriptor_extension(segment_descriptor segment_descriptor); + + private: + uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 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/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7db9583..5901998 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -29,7 +29,19 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + auto reload_gdtr() -> void + { + // asm volatile("pushq $0x8\n\t" // Push new CS + // "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX + // "pushq %%rax\n\t" // Push return address + // "lretq\n" // Far return (loads CS:RIP) + // "1:\n\t" // Label to return to + // : + // : + // : "rax", "memory"); + + kernel::cpu::call(KERNEL_CODE_POINTER); + } auto user_mode_main() -> void { @@ -83,9 +95,7 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the - // cs register (See https://www.felixcloutier.com/x86/sysret). - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR - 0x10; + uint64_t user_cs = KERNEL_CODE_SEGMENT_SELECTOR; uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); @@ -102,17 +112,17 @@ namespace teachos::arch::context_switching { kernel::cpu::clear_interrupt_flag(); - segment_descriptor_table::update_global_descriptor_table_register(); + segment_descriptor_table::update_gdtr(); interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - reload_global_descriptor_table_register(); + reload_gdtr(); segment_descriptor_table::update_task_state_segment_register(); kernel::cpu::set_interrupt_flag(); initalized = true; } - descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index a497632..dd22603 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -1,11 +1,11 @@ #include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" #include "arch/context_switching/segment_descriptor_table/task_state_segment.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/gdtr.hpp" #include "arch/kernel/cpu/tr.hpp" -#include "arch/stl/vector.hpp" namespace teachos::arch::context_switching::segment_descriptor_table { @@ -26,7 +26,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - flags |= gdt_flags::UPPER_BOUND; access_level |= access_byte::WRITABLE; } @@ -34,7 +33,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table return segment_descriptor; } - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor + auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor { constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL | @@ -45,43 +44,51 @@ namespace teachos::arch::context_switching::segment_descriptor_table return tss_descriptor; } - auto create_global_descriptor_table() -> global_descriptor_table + auto create_gdt() -> global_descriptor_table * { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor_base const null_segment{segment_descriptor{0}}; + segment_descriptor_base const kernel_code_segment{ + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL)}; + segment_descriptor_base const kernel_data_segment{ + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL)}; + segment_descriptor_base const user_code_segment{ + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER)}; + segment_descriptor_base const user_data_segment{ + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER)}; // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - - global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } + segment_descriptor const tss_descriptor = create_tss_descriptor(tss); + segment_descriptor_base const tss_descriptor_base{tss_descriptor}; + segment_descriptor_extension const tss_descriptor_extension{tss_descriptor}; + + decltype(auto) gdt = new global_descriptor_table{}; + gdt->null = null_segment; + gdt->kernel_code = kernel_code_segment; + gdt->kernel_data = kernel_data_segment; + gdt->user_code = user_code_segment; + gdt->user_data = user_data_segment; + gdt->tss_low = tss_descriptor_base; + gdt->tss_high = tss_descriptor_extension; + + return gdt; + }; } // namespace - auto get_or_create_global_descriptor_table() -> global_descriptor_table & + auto get_or_create_gdt() -> global_descriptor_table & { // Global Descriptor Table needs to be kept alive - static global_descriptor_table gdt = create_global_descriptor_table(); - return gdt; + static global_descriptor_table * gdt = create_gdt(); + return *gdt; } - auto update_global_descriptor_table_register() -> void + auto update_gdtr() -> void { - decltype(auto) gdt = get_or_create_global_descriptor_table(); + decltype(auto) gdt = get_or_create_gdt(); // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. - global_descriptor_table_pointer gdt_pointer{static_cast((gdt.size() * sizeof(segment_descriptor)) - 1), - gdt.data()}; + global_descriptor_table_pointer gdt_pointer{static_cast((7 * sizeof(seg_desc)) - 1), &gdt.null}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); @@ -92,11 +99,11 @@ namespace teachos::arch::context_switching::segment_descriptor_table auto update_task_state_segment_register() -> void { - decltype(auto) gdt = get_or_create_global_descriptor_table(); + get_or_create_gdt(); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating // offset in bytes to the start of the segment descriptor (5 * 16) = 80 - uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + uint16_t const tss_selector = (7 - 1) * sizeof(segment_descriptor_table::segment_descriptor); kernel::cpu::load_task_register(tss_selector); auto const stored_task_register = kernel::cpu::store_task_register(); diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp index a4a5de8..b7d2da4 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -2,8 +2,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, - segment_descriptor * address) + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, seg_desc * address) : table_length(table_length) , address(address) { diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp index 74f93b2..e74156b 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp @@ -32,4 +32,15 @@ namespace teachos::arch::context_switching::segment_descriptor_table return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT : segment_descriptor_type::DATA_SEGMENT; } + + auto segment_descriptor::get_limit_1() -> uint16_t { return _limit_1; } + + auto segment_descriptor::get_base_1() -> uint32_t { return _base_1; } + + auto segment_descriptor::get_access() -> access_byte { return _access; } + + auto segment_descriptor::get_flag() -> gdt_flags { return _flag; } + + auto segment_descriptor::get_base_2() -> uint64_t { return _base_2; } + } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp new file mode 100644 index 0000000..f82dbb9 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor_base::segment_descriptor_base(segment_descriptor segment_descriptor) + : _limit_1(segment_descriptor.get_limit_1()) + , _base_1(segment_descriptor.get_base_1()) + , _access(segment_descriptor.get_access()) + , _flag(segment_descriptor.get_flag()) + { + // Nothing to do + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp new file mode 100644 index 0000000..b2649d0 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor_extension::segment_descriptor_extension(segment_descriptor segment_descriptor) + : _base_2(segment_descriptor.get_base_2()) + { + // Nothing to do + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp index 98fa248..932d248 100644 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -4,6 +4,7 @@ namespace teachos::arch::kernel::cpu { auto call(far_pointer pointer) -> void { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + // asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + asm volatile("ljmp *%0" : : "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 099a7fbbc35a71f98553fa39899f2d17c555242f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 2 May 2025 14:49:06 +0000 Subject: Finish implementing 8-byte GDT entries and syscall arg loads. --- arch/x86_64/CMakeLists.txt | 1 - .../segment_selector.hpp | 4 +- .../global_descriptor_table.hpp | 2 +- .../global_descriptor_table_pointer.hpp | 17 +---- .../segment_descriptor.hpp | 83 ---------------------- .../segment_descriptor_base.hpp | 45 +++++++++++- .../segment_descriptor_extension.hpp | 57 +++++++++++++-- .../segment_selector.cpp | 2 + arch/x86_64/src/context_switching/main.cpp | 58 ++++++++++----- .../global_descriptor_table.cpp | 75 +++++++++---------- .../global_descriptor_table_pointer.cpp | 2 +- .../segment_descriptor.cpp | 46 ------------ .../segment_descriptor_base.cpp | 35 +++++++-- .../segment_descriptor_extension.cpp | 18 ++++- arch/x86_64/src/kernel/cpu/call.cpp | 4 +- arch/x86_64/src/kernel/cpu/tr.cpp | 8 +-- 16 files changed, 225 insertions(+), 232 deletions(-) delete mode 100644 arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 58afdb5..21dbddd 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -97,7 +97,6 @@ target_sources("_context" PRIVATE "src/context_switching/segment_descriptor_table/gdt_flags.cpp" "src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp" "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp" - "src/context_switching/segment_descriptor_table/segment_descriptor.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp" "src/context_switching/main.cpp" 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 index 8748448..5be449f 100644 --- 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 @@ -79,11 +79,11 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto operator|=(std::bitset<3U> other) -> void; /** - * @brief Combines all bits in the underlying data in the correct order to return a raw value containing all bits. + * @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 { return static_cast(_flags) | (static_cast(_index) << 3U); } + operator uint16_t() const; private: uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. 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 index 84a24a2..44f2692 100644 --- 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 @@ -30,7 +30,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table * @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_task_state_segment_register() -> void; + auto update_tss_register() -> void; } // namespace teachos::arch::context_switching::segment_descriptor_table 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 index c54647d..292ff70 100644 --- 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 @@ -1,24 +1,13 @@ #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/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" #include "arch/stl/vector.hpp" #include namespace teachos::arch::context_switching::segment_descriptor_table { - struct __attribute__((packed, aligned(8))) global_descriptor_table - { - segment_descriptor_base null; - segment_descriptor_base kernel_code; - segment_descriptor_base kernel_data; - segment_descriptor_base user_code; - segment_descriptor_base user_data; - segment_descriptor_base tss_low; - segment_descriptor_extension tss_high; - }; + using global_descriptor_table = stl::vector; /** * @brief Represents a pointer to the Global Descriptor Table (GDT). @@ -36,7 +25,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Constructor. */ - global_descriptor_table_pointer(uint16_t table_length, seg_desc * address); + global_descriptor_table_pointer(uint16_t table_length, uint64_t * address); /** * @brief Defaulted three-way comparsion operator. @@ -45,7 +34,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table private: uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - seg_desc * address = {}; ///< Non-owning pointer to the GDT base address. + uint64_t * address = {}; ///< Non-owning pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp deleted file mode 100644 index ccd604d..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_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 -{ - __extension__ typedef __int128 int128_t; - __extension__ typedef unsigned __int128 uint128_t; - - struct seg_desc - { - private: - uint64_t : 64; ///< Makes sure the struct is 8-Bytes big - }; - - /** - * @brief Defines helper function for all states and the actual data the segment descriptor can have. - */ - struct [[gnu::packed]] segment_descriptor - { - /** - * @brief Default Constructor. - */ - segment_descriptor() = default; - - /** - * @brief Constructor. - * - * @note Created segment descriptor copies the given bytes into theese components ending with a 32 bit reserved - * field that has to be used, because the 64-bit segment descriptor needs to be big enough for two 32-bit segment - * descriptor. - * - 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(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(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit); - - auto get_limit_1() -> uint16_t; - auto get_base_1() -> uint32_t; - auto get_access() -> access_byte; - auto get_flag() -> gdt_flags; - auto get_base_2() -> uint64_t; - - /** - * @brief Calculates the underlying segment type that this segement descriptor is describing. - */ - auto get_segment_type() const -> segment_descriptor_type; - - /** - * @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 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) - uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 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_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 index 18c9da1..933fb4d 100644 --- 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 @@ -3,7 +3,6 @@ #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.hpp" #include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" namespace teachos::arch::context_switching::segment_descriptor_table @@ -11,7 +10,7 @@ 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 : seg_desc + struct [[gnu::packed]] segment_descriptor_base { /** * @brief Default Constructor. @@ -20,14 +19,54 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @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. */ - segment_descriptor_base(segment_descriptor 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 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 index 0b724f2..40bcc8a 100644 --- 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 @@ -1,16 +1,17 @@ #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.hpp" - -#include +#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 : seg_desc + struct [[gnu::packed]] segment_descriptor_extension { /** * @brief Default Constructor. @@ -19,12 +20,54 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @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. */ - segment_descriptor_extension(segment_descriptor segment_descriptor); + auto operator==(segment_descriptor_extension const & other) const -> bool = default; private: - uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + // 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 diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp index 0e29356..8568447 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -8,4 +8,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table } auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } + + segment_selector::operator uint16_t() const { return *reinterpret_cast(this); } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5901998..7449d84 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -31,14 +31,14 @@ namespace teachos::arch::context_switching auto reload_gdtr() -> void { - // asm volatile("pushq $0x8\n\t" // Push new CS - // "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX - // "pushq %%rax\n\t" // Push return address - // "lretq\n" // Far return (loads CS:RIP) - // "1:\n\t" // Label to return to - // : - // : - // : "rax", "memory"); + /*asm volatile("pushq $0x8\n\t" // Push new CS + "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX + "pushq %%rax\n\t" // Push return address + "lretq\n" // Far return (loads CS:RIP) + "1:\n\t" // Label to return to + : + : + : "rax", "memory");*/ kernel::cpu::call(KERNEL_CODE_POINTER); } @@ -57,21 +57,33 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - uint64_t new_value = 60U; + uint64_t syscall_number = 60U; asm volatile("mov %[input], %%rax" : /* no output from call */ - : [input] "r"(new_value) + : [input] "r"(syscall_number) : "memory"); asm volatile("syscall"); - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); + // TODO: Reading RAX value does not work because the read itself changes the RAX value?! + // asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_value)); + + // TODO: Causes a general protection fault after the sysreturn? + // If removed instead it will cause a general protection fault after leaving this main method to return to kernel + // mode. But CS and SS are still configured for User mode. + /*video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black);*/ } auto syscall_handler() -> void { - uint64_t syscall_number{}; + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + asm volatile("mov %%rdi, %[output]" : [output] "=r"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=r"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=r"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=r"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=r"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=r"(arg_5)); switch (syscall_number) { @@ -85,7 +97,17 @@ namespace teachos::arch::context_switching break; } - asm volatile("sysretq"); + uint64_t result = 0U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "r"(result) + : "memory"); + + // Use SYSRET instead of SYSRETQ, because the latter would add 0x10 to bits [48:63] of IA32_STAR_ADDRESS for the + // Code Segment. But only add 0x8 to bits [48:63] of IA32_STAR_ADDRESS for the Stack Segment, which means either + // the Stack Segment or Code Segment is wrong. Whereas the former does not add 0x10 for the Code Segment and + // therefore fixes the aformentioned issue. + asm volatile("sysret"); } auto enable_systemcall() -> void @@ -94,9 +116,9 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t user_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const user_cs = USER_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); @@ -116,7 +138,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::update_interrupt_descriptor_table_register(); reload_gdtr(); - segment_descriptor_table::update_task_state_segment_register(); + segment_descriptor_table::update_tss_register(); kernel::cpu::set_interrupt_flag(); initalized = true; diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index dd22603..d692e51 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -1,8 +1,6 @@ #include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" #include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" -#include "arch/context_switching/segment_descriptor_table/task_state_segment.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/gdtr.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -12,7 +10,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table namespace { auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level) - -> segment_descriptor + -> segment_descriptor_base { uint64_t const base = 0x0; std::bitset<20U> const limit{0xFFFFF}; @@ -29,57 +27,53 @@ namespace teachos::arch::context_switching::segment_descriptor_table access_level |= access_byte::WRITABLE; } - segment_descriptor const segment_descriptor{access_level, flags, base, limit}; - return segment_descriptor; + segment_descriptor_base const segment_descriptor_base{access_level, flags, base, limit}; + return segment_descriptor_base; } - auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor + auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor_extension { constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL | access_byte::TASK_STATE_SEGMENT_AVAILABLE}; gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; - segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), - TSS_LIMIT}; + segment_descriptor_extension const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), + TSS_LIMIT}; return tss_descriptor; } - auto create_gdt() -> global_descriptor_table * + auto create_gdt() -> global_descriptor_table { - segment_descriptor_base const null_segment{segment_descriptor{0}}; - segment_descriptor_base const kernel_code_segment{ - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL)}; - segment_descriptor_base const kernel_data_segment{ - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL)}; - segment_descriptor_base const user_code_segment{ - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER)}; - segment_descriptor_base const user_data_segment{ - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER)}; + segment_descriptor_base const null_segment{0}; + segment_descriptor_base const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor_base const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor_base const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor_base const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_tss_descriptor(tss); - segment_descriptor_base const tss_descriptor_base{tss_descriptor}; - segment_descriptor_extension const tss_descriptor_extension{tss_descriptor}; - - decltype(auto) gdt = new global_descriptor_table{}; - gdt->null = null_segment; - gdt->kernel_code = kernel_code_segment; - gdt->kernel_data = kernel_data_segment; - gdt->user_code = user_code_segment; - gdt->user_data = user_data_segment; - gdt->tss_low = tss_descriptor_base; - gdt->tss_high = tss_descriptor_extension; - - return gdt; - }; + segment_descriptor_extension const tss_descriptor = create_tss_descriptor(tss); + + global_descriptor_table global_descriptor_table{null_segment, + kernel_code_segment, + kernel_data_segment, + user_code_segment, + user_data_segment, + tss_descriptor.get_first_gdt_entry(), + tss_descriptor.get_second_gdt_entry()}; + return global_descriptor_table; + } } // namespace auto get_or_create_gdt() -> global_descriptor_table & { // Global Descriptor Table needs to be kept alive - static global_descriptor_table * gdt = create_gdt(); - return *gdt; + static global_descriptor_table gdt = create_gdt(); + return gdt; } auto update_gdtr() -> void @@ -88,7 +82,8 @@ namespace teachos::arch::context_switching::segment_descriptor_table // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. - global_descriptor_table_pointer gdt_pointer{static_cast((7 * sizeof(seg_desc)) - 1), &gdt.null}; + uint16_t gdt_size = static_cast((gdt.size() * sizeof(segment_descriptor_base)) - 1); + global_descriptor_table_pointer gdt_pointer{gdt_size, gdt.data()}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); @@ -97,13 +92,13 @@ namespace teachos::arch::context_switching::segment_descriptor_table "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); } - auto update_task_state_segment_register() -> void + auto update_tss_register() -> void { - get_or_create_gdt(); + decltype(auto) gdt = get_or_create_gdt(); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // offset in bytes to the start of the segment descriptor (5 * 16) = 80 - uint16_t const tss_selector = (7 - 1) * sizeof(segment_descriptor_table::segment_descriptor); + // offset in bytes to the start of the segment descriptor (5 * 8) = 40 + uint16_t tss_selector = (gdt.size() * sizeof(segment_descriptor_base)) - sizeof(segment_descriptor_extension); kernel::cpu::load_task_register(tss_selector); auto const stored_task_register = kernel::cpu::store_task_register(); diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp index b7d2da4..79088b8 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -2,7 +2,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, seg_desc * address) + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, uint64_t * address) : table_length(table_length) , address(address) { diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp deleted file mode 100644 index e74156b..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - segment_descriptor::segment_descriptor(uint128_t flags) - : _limit_1(flags) - , _base_1(flags >> 16U) - , _access(flags >> 40U) - , _flag(flags >> 52U, flags >> 48U) - , _base_2(flags >> 56U) - { - // Nothing to do. - } - - segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, - std::bitset<20U> limit) - : _limit_1(limit.to_ulong()) - , _base_1(base) - , _access(access_byte) - , _flag(flags) - , _base_2(base >> 24U) - { - // Nothing to do - } - - auto segment_descriptor::get_segment_type() const -> segment_descriptor_type - { - if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) - { - return segment_descriptor_type::SYSTEM_SEGMENT; - } - return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; - } - - auto segment_descriptor::get_limit_1() -> uint16_t { return _limit_1; } - - auto segment_descriptor::get_base_1() -> uint32_t { return _base_1; } - - auto segment_descriptor::get_access() -> access_byte { return _access; } - - auto segment_descriptor::get_flag() -> gdt_flags { return _flag; } - - auto segment_descriptor::get_base_2() -> uint64_t { return _base_2; } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp index f82dbb9..04804d9 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp @@ -2,12 +2,37 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - segment_descriptor_base::segment_descriptor_base(segment_descriptor segment_descriptor) - : _limit_1(segment_descriptor.get_limit_1()) - , _base_1(segment_descriptor.get_base_1()) - , _access(segment_descriptor.get_access()) - , _flag(segment_descriptor.get_flag()) + segment_descriptor_base::segment_descriptor_base(uint64_t flags) + : _limit_1(flags) + , _base_1(flags >> 16U) + , _access(flags >> 40U) + , _flag(flags >> 52U, flags >> 48U) + , _base_2(flags >> 56U) + { + // Nothing to do. + } + + segment_descriptor_base::segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, + std::bitset<20U> limit) + : _limit_1(limit.to_ulong()) + , _base_1(base) + , _access(access_byte) + , _flag(flags) + , _base_2(base >> 24U) { // Nothing to do } + + auto segment_descriptor_base::get_segment_type() const -> segment_descriptor_type + { + if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) + { + return segment_descriptor_type::SYSTEM_SEGMENT; + } + return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; + } + + segment_descriptor_base::operator uint64_t() const { return *reinterpret_cast(this); } + } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp index b2649d0..a28ec9b 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp @@ -2,9 +2,23 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - segment_descriptor_extension::segment_descriptor_extension(segment_descriptor segment_descriptor) - : _base_2(segment_descriptor.get_base_2()) + segment_descriptor_extension::segment_descriptor_extension(uint128_t flags) + : _base(flags) + , _base_3(flags >> 64U) + { + // Nothing to do. + } + + segment_descriptor_extension::segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, + std::bitset<20U> limit) + : _base(access_byte, flags, base, limit) + , _base_3(base >> 32U) { // Nothing to do } + + auto segment_descriptor_extension::get_first_gdt_entry() const -> segment_descriptor_base { return _base; } + + auto segment_descriptor_extension::get_second_gdt_entry() const -> uint64_t { return _base_3; } + } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp index 932d248..6564b76 100644 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::kernel::cpu { auto call(far_pointer pointer) -> void { - // asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - asm volatile("ljmp *%0" : : "m"(pointer)); + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + // asm volatile("ljmp *%0" : : "m"(pointer)); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index e281189..a435540 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -11,12 +11,6 @@ namespace teachos::arch::kernel::cpu auto load_task_register(uint16_t gdt_offset) -> void { - // asm volatile("ltr %[input]" : /* no output from call */ : [input] "R"(gdt_offset)); - // https://www.scs.stanford.edu/05au-cs240c/lab/i386/s07_03.htm - asm volatile("mov %[input], %%ax\n" - "ltr %%ax\n" - : /* no output from call */ - : [input] "r"(gdt_offset) - : "ax"); + asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 4b8674bee6089aef1e2c6b9064c6109f1cd392da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 3 May 2025 07:24:55 +0000 Subject: Remove zomby code and fix 32-bit compability crash --- arch/x86_64/src/context_switching/main.cpp | 38 +++++++----------------------- arch/x86_64/src/kernel/cpu/call.cpp | 1 - 2 files changed, 8 insertions(+), 31 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7449d84..06c0810 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -20,8 +20,6 @@ namespace teachos::arch::context_switching constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - constexpr interrupt_descriptor_table::segment_selector KERNEL_DATA_SEGMENT_SELECTOR{ - 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ @@ -29,19 +27,7 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - auto reload_gdtr() -> void - { - /*asm volatile("pushq $0x8\n\t" // Push new CS - "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX - "pushq %%rax\n\t" // Push return address - "lretq\n" // Far return (loads CS:RIP) - "1:\n\t" // Label to return to - : - : - : "rax", "memory");*/ - - kernel::cpu::call(KERNEL_CODE_POINTER); - } + auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } auto user_mode_main() -> void { @@ -64,14 +50,11 @@ namespace teachos::arch::context_switching : "memory"); asm volatile("syscall"); - // TODO: Reading RAX value does not work because the read itself changes the RAX value?! - // asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_value)); - - // TODO: Causes a general protection fault after the sysreturn? - // If removed instead it will cause a general protection fault after leaving this main method to return to kernel - // mode. But CS and SS are still configured for User mode. - /*video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black);*/ + // Reading RAX decrements value by one in 32-bit compatability mode it also crashes vga write, therfore use + // SYSRETQ instead of SYSRET so we do not return into 32-bit compatability mode. + asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); } auto syscall_handler() -> void @@ -103,11 +86,7 @@ namespace teachos::arch::context_switching : [input] "r"(result) : "memory"); - // Use SYSRET instead of SYSRETQ, because the latter would add 0x10 to bits [48:63] of IA32_STAR_ADDRESS for the - // Code Segment. But only add 0x8 to bits [48:63] of IA32_STAR_ADDRESS for the Stack Segment, which means either - // the Stack Segment or Code Segment is wrong. Whereas the former does not add 0x10 for the Code Segment and - // therefore fixes the aformentioned issue. - asm volatile("sysret"); + asm volatile("sysretq"); } auto enable_systemcall() -> void @@ -117,8 +96,7 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const user_cs = USER_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (user_cs << 48); + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp index 6564b76..98fa248 100644 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -5,6 +5,5 @@ namespace teachos::arch::kernel::cpu auto call(far_pointer pointer) -> void { asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - // asm volatile("ljmp *%0" : : "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 5a8c9d2f2e4a3d2810f81c35070c6ef0926cfdd1 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 3 May 2025 09:45:45 +0000 Subject: write wrapper function for syscall --- arch/x86_64/CMakeLists.txt | 2 + .../arch/context_switching/syscall/main.hpp | 28 +++++++++ .../context_switching/syscall/syscall_handler.hpp | 23 +++++++ .../generic_interrupt_handler.hpp | 8 --- .../interrupt_descriptor_table.cpp | 5 -- arch/x86_64/src/context_switching/main.cpp | 71 +++------------------- arch/x86_64/src/context_switching/syscall/main.cpp | 57 +++++++++++++++++ .../context_switching/syscall/syscall_handler.cpp | 68 +++++++++++++++++++++ .../generic_interrupt_handler.cpp | 26 -------- arch/x86_64/src/kernel/cpu/control_register.cpp | 6 -- 10 files changed, 186 insertions(+), 108 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/syscall/main.hpp create mode 100644 arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp create mode 100644 arch/x86_64/src/context_switching/syscall/main.cpp create mode 100644 arch/x86_64/src/context_switching/syscall/syscall_handler.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 21dbddd..0b4eafe 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -100,6 +100,8 @@ target_sources("_context" PRIVATE "src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp" "src/context_switching/main.cpp" + "src/context_switching/syscall/main.cpp" + "src/context_switching/syscall/syscall_handler.cpp" "src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp" "src/context_switching/interrupt_descriptor_table/idt_flags.cpp" "src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp" diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp new file mode 100644 index 0000000..c75268a --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -0,0 +1,28 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP + +#include "arch/context_switching/syscall/syscall_handler.hpp" + +#include +#include +#include + +namespace teachos::arch::context_switching::syscall +{ + struct arguments + { + uint64_t arg_0{}; + uint64_t arg_1{}; + uint64_t arg_2{}; + uint64_t arg_3{}; + uint64_t arg_4{}; + uint64_t arg_5{}; + }; + + auto enable_syscall() -> void; + + auto syscall(type syscall_number, arguments args = {}) -> uint64_t; + +} // 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_handler.hpp b/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp new file mode 100644 index 0000000..e076995 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp @@ -0,0 +1,23 @@ +#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 +{ + enum type : uint64_t + { + WRITE = 1U + }; + + /** + * @brief Handler for SYSCALL instruction. Calls a specific implementation based + * on the register RAX. + * + * @return Returns with 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/interrupt_handling/generic_interrupt_handler.hpp b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp index 866d15d..8091a58 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -29,14 +29,6 @@ namespace teachos::arch::interrupt_handling [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto generic_interrupt_handler(interrupt_frame * frame) -> void; - /** - * @brief Interrupt handler function for syscalls (INT 0x80). - * - * @param frame Pointer to the interrupt frame containing CPU state. - */ - [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] - auto syscall_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/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index c041198..7aa0859 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -26,11 +26,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } - interrupt_descriptor_table.at(0x80) = { - segment_selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}, ist_offset{0U}, - idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::TRAP_GATE | idt_flags::PRESENT}, - uint64_t{reinterpret_cast(interrupt_handling::syscall_interrupt_handler)}}; - return interrupt_descriptor_table; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 06c0810..7fe159e 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,11 +1,11 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/msr.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/video/vga/text.hpp" @@ -14,10 +14,6 @@ namespace teachos::arch::context_switching { namespace { - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, @@ -31,8 +27,6 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); - // RFLAGS is saved into R11, RIP of the next instruction into RCX // Required for SYSRETURN to know where to return too. // Additional state needs to be saved by calling convention: @@ -43,65 +37,16 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - uint64_t syscall_number = 60U; - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "r"(syscall_number) - : "memory"); - asm volatile("syscall"); - - // Reading RAX decrements value by one in 32-bit compatability mode it also crashes vga write, therfore use - // SYSRETQ instead of SYSRET so we do not return into 32-bit compatability mode. - asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } - auto syscall_handler() -> void - { - uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; - asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); - asm volatile("mov %%rdi, %[output]" : [output] "=r"(arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=r"(arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=r"(arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=r"(arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=r"(arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=r"(arg_5)); - - switch (syscall_number) + const char syscall_message[32] = "Successfully entered user mode!"; + auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); + + if (!error) { - case 1: - // Write VGA - break; - case 60U: - // Exit - break; - default: - break; + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); } - - uint64_t result = 0U; - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "r"(result) - : "memory"); - - asm volatile("sysretq"); } - - auto enable_systemcall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -129,7 +74,7 @@ namespace teachos::arch::context_switching auto switch_to_user_mode() -> void { - enable_systemcall(); + syscall::enable_syscall(); switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); } diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp new file mode 100644 index 0000000..e90f503 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -0,0 +1,57 @@ +#include "arch/context_switching/syscall/main.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" +#include "arch/kernel/cpu/msr.hpp" + +#include + +namespace teachos::arch::context_switching::syscall +{ + namespace + { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + + } // namespace + + auto enable_syscall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); + + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } + + auto syscall(type syscall_number, arguments args) -> uint64_t + { + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(syscall_number) + : "memory"); + + asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); + asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); + asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); + asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); + asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); + asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); + + asm volatile("syscall"); + + uint64_t result{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(result)); + return result; + } + +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp new file mode 100644 index 0000000..f6e1c9e --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -0,0 +1,68 @@ +#include "arch/context_switching/syscall/syscall_handler.hpp" + +#include "arch/exception_handling/panic.hpp" +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::context_switching::syscall +{ + + namespace + { + auto write_to_vga_buffer(uint64_t buffer) + { + video::vga::text::write(reinterpret_cast(buffer), + video::vga::text::common_attributes::green_on_black); + } + } // namespace + + auto syscall_handler() -> void + { + // Saving state of rcx and r11 because it is required by sysretq to function. + // Calls to other functions potentially overwrite these registers, because of + // callee saved calling convention. + uint64_t return_instruction_pointer, rflags = {}; + asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); + asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); + + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); + + // RAX is read last, because paired with our type enum, we can use it to check + // if the register has been written by the compiled code between executing the syscall + // and now. + asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); + + switch (static_cast(syscall_number)) + { + case WRITE: + write_to_vga_buffer(arg_0); + break; + default: + teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); + break; + } + + uint64_t result = 0U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(result) + : "memory"); + + asm volatile("mov %[input], %%rcx" + : /* no output from call */ + : [input] "m"(return_instruction_pointer) + : "memory"); + asm volatile("mov %[input], %%r11" + : /* no output from call */ + : [input] "m"(rflags) + : "memory"); + + asm volatile("sysretq"); + } + +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 60fb50c..8e2c62d 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -9,30 +9,4 @@ namespace teachos::arch::interrupt_handling (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } - - auto syscall_interrupt_handler(interrupt_frame * frame) -> void - { - // RDI, RSI, RDX, RCX, R8, R9 - // RDI -> SYSCALL number - // Others are arguments - - // TODO: The registers are not available here. We need to set them up on the stack - // and access them via argument. - - uint64_t syscall_number{}; - asm volatile("mov %%rdi, %0" : "=r"(syscall_number)); - - // Handle system call based on the number - switch (syscall_number) - { - case 1: - video::vga::text::write("SYSCALL 1.", video::vga::text::common_attributes::green_on_black); - break; - default: - // Handle unknown syscall - break; - } - - (void)frame; - } } // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp index a39a360..41b8cd7 100644 --- a/arch/x86_64/src/kernel/cpu/control_register.cpp +++ b/arch/x86_64/src/kernel/cpu/control_register.cpp @@ -23,9 +23,6 @@ namespace teachos::arch::kernel::cpu case control_register::CR4: asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); break; - default: - exception_handling::panic("[Control Register] Attempted to read non-existent or reserved control register"); - break; } return current_value; } @@ -58,9 +55,6 @@ namespace teachos::arch::kernel::cpu : [input] "r"(new_value) : "memory"); break; - default: - exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); - break; } } -- cgit v1.2.3 From 4b4ca98376cb4bdf97fd910b7e2ca78628b0a8ee Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 3 May 2025 09:51:15 +0000 Subject: rename syscall result variable --- arch/x86_64/src/context_switching/syscall/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index e90f503..9ac63ce 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -49,9 +49,9 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - uint64_t result{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(result)); - return result; + uint64_t error{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(error)); + return error; } } // namespace teachos::arch::context_switching::syscall \ No newline at end of file -- cgit v1.2.3 From 4d4e23116284f41329ea809e2bda86feea1b325c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 10:51:12 +0000 Subject: fix returning from syscall --- arch/x86_64/src/context_switching/main.cpp | 3 ++- arch/x86_64/src/context_switching/syscall/syscall_handler.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7fe159e..6c6ec1a 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -27,6 +27,7 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { + // TODO: Remove or replace this wall of text // RFLAGS is saved into R11, RIP of the next instruction into RCX // Required for SYSRETURN to know where to return too. // Additional state needs to be saved by calling convention: @@ -38,7 +39,7 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - const char syscall_message[32] = "Successfully entered user mode!"; + const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); if (!error) diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index f6e1c9e..759a092 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -12,6 +12,7 @@ namespace teachos::arch::context_switching::syscall { video::vga::text::write(reinterpret_cast(buffer), video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); } } // namespace @@ -62,7 +63,8 @@ namespace teachos::arch::context_switching::syscall : [input] "m"(rflags) : "memory"); - asm volatile("sysretq"); + asm volatile("leave\n" + "sysretq"); } } // namespace teachos::arch::context_switching::syscall \ No newline at end of file -- cgit v1.2.3 From ccb0fcb78c0d22ebaeb9aa37f1941b0d44c98038 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 11:07:48 +0000 Subject: move user-mode code into own namespace and linker section --- arch/x86_64/CMakeLists.txt | 8 +++++ .../generic_interrupt_handler.hpp | 2 +- arch/x86_64/include/arch/user/main.hpp | 10 ++++++ arch/x86_64/src/context_switching/main.cpp | 27 ++-------------- arch/x86_64/src/user/main.cpp | 36 ++++++++++++++++++++++ 5 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 arch/x86_64/include/arch/user/main.hpp create mode 100644 arch/x86_64/src/user/main.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 0b4eafe..1ce2731 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -118,6 +118,14 @@ target_sources("_interrupt_handling" PRIVATE "src/interrupt_handling/generic_interrupt_handler.cpp" ) +#[============================================================================[ +# The User code +#]============================================================================] + +target_sources("_context" PRIVATE + "src/user/main.cpp" +) + #[============================================================================[ # The Bootable ISO Image #]============================================================================] 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 index 8091a58..2d26668 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -26,7 +26,7 @@ namespace teachos::arch::interrupt_handling * * @param frame Pointer to the interrupt frame containing CPU state. */ - [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] + [[gnu::interrupt]] auto generic_interrupt_handler(interrupt_frame * frame) -> void; } // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/include/arch/user/main.hpp b/arch/x86_64/include/arch/user/main.hpp new file mode 100644 index 0000000..7127d07 --- /dev/null +++ b/arch/x86_64/include/arch/user/main.hpp @@ -0,0 +1,10 @@ +#ifndef TEACHOS_ARCH_X86_64_USER_MAIN_HPP +#define TEACHOS_ARCH_X86_64_USER_MAIN_HPP + +namespace teachos::arch::user +{ + auto main() -> void; + +} // namespace teachos::arch::user + +#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 6c6ec1a..a112924 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -8,6 +8,7 @@ #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" +#include "arch/user/main.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching @@ -24,30 +25,6 @@ namespace teachos::arch::context_switching 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } - - auto user_mode_main() -> void - { - // TODO: Remove or replace this wall of text - // RFLAGS is saved into R11, RIP of the next instruction into RCX - // Required for SYSRETURN to know where to return too. - // Additional state needs to be saved by calling convention: - - // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) - // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 - // Not used registers: RBX, RSP, R12, R13, R14 - - // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: - // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - - const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); - - if (!error) - { - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } - } } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -76,7 +53,7 @@ namespace teachos::arch::context_switching auto switch_to_user_mode() -> void { syscall::enable_syscall(); - switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); } auto switch_context(interrupt_descriptor_table::segment_selector data_segment, diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp new file mode 100644 index 0000000..6d8eea7 --- /dev/null +++ b/arch/x86_64/src/user/main.cpp @@ -0,0 +1,36 @@ +#include "arch/user/main.hpp" + +#include "arch/context_switching/syscall/main.hpp" + +// TODO: Disallow this import +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::user +{ + + [[gnu::section(".user_text")]] + auto main() -> void + { + // TODO: Remove or replace this wall of text + // RFLAGS is saved into R11, RIP of the next instruction into RCX + // Required for SYSRETURN to know where to return too. + // Additional state needs to be saved by calling convention: + + // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) + // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 + // Not used registers: RBX, RSP, R12, R13, R14 + + // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: + // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html + + const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + auto error = context_switching::syscall::syscall(context_switching::syscall::WRITE, + {reinterpret_cast(&syscall_message)}); + + if (!error) + { + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); + } + } +} // namespace teachos::arch::user \ No newline at end of file -- cgit v1.2.3 From f83727a0c8913d19415c2ad482c70ee7373f6f3f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 11:26:29 +0000 Subject: add user_text linker section and temporarily add elf_sections.txt --- arch/x86_64/scripts/kernel.ld | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 806adb5..239d026 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -90,9 +90,9 @@ SECTIONS *(.text*) } - .interrupt_text ALIGN(4K) : AT(ADDR (.interrupt_text)) + .user_text ALIGN(4K) : AT(ADDR (.user_text)) { - *(.interrupt_text) + *(.user_text) } .rodata ALIGN(4K) : AT (ADDR (.rodata)) -- cgit v1.2.3 From c1dff44858ebdb3cd5a49e84179796e44e7eb91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 06:41:31 +0000 Subject: Fix recursive include using extra file --- arch/x86_64/CMakeLists.txt | 1 + .../arch/context_switching/syscall/main.hpp | 20 ++++++++----- .../context_switching/syscall/syscall_enable.hpp | 10 +++++++ .../context_switching/syscall/syscall_handler.hpp | 7 +---- arch/x86_64/include/arch/user/main.hpp | 2 +- arch/x86_64/src/context_switching/main.cpp | 5 +--- arch/x86_64/src/context_switching/syscall/main.cpp | 35 ++-------------------- .../context_switching/syscall/syscall_enable.cpp | 32 ++++++++++++++++++++ .../context_switching/syscall/syscall_handler.cpp | 13 +++++--- arch/x86_64/src/user/main.cpp | 7 ++--- 10 files changed, 73 insertions(+), 59 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp create mode 100644 arch/x86_64/src/context_switching/syscall/syscall_enable.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1ce2731..3d6d2c7 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -101,6 +101,7 @@ target_sources("_context" PRIVATE "src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp" "src/context_switching/main.cpp" "src/context_switching/syscall/main.cpp" + "src/context_switching/syscall/syscall_enable.cpp" "src/context_switching/syscall/syscall_handler.cpp" "src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp" "src/context_switching/interrupt_descriptor_table/idt_flags.cpp" diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index c75268a..ae4c2db 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -1,14 +1,22 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP -#include "arch/context_switching/syscall/syscall_handler.hpp" - -#include #include -#include namespace teachos::arch::context_switching::syscall { + enum class type : uint64_t + { + WRITE = 1U + }; + + enum class error + { + OK = 0U, + }; + + constexpr bool operator!(error e) { return e == error::OK; } + struct arguments { uint64_t arg_0{}; @@ -19,9 +27,7 @@ namespace teachos::arch::context_switching::syscall uint64_t arg_5{}; }; - auto enable_syscall() -> void; - - auto syscall(type syscall_number, arguments args = {}) -> uint64_t; + auto syscall(type syscall_number, arguments args = {}) -> error; } // namespace teachos::arch::context_switching::syscall 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 new file mode 100644 index 0000000..59b97b2 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp @@ -0,0 +1,10 @@ +#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 +{ + 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 index e076995..2e7bcd1 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/syscall_handler.hpp @@ -5,16 +5,11 @@ namespace teachos::arch::context_switching::syscall { - enum type : uint64_t - { - WRITE = 1U - }; - /** * @brief Handler for SYSCALL instruction. Calls a specific implementation based * on the register RAX. * - * @return Returns with SYSRETQ + * @return Returns with LEAVE, SYSRETQ */ auto syscall_handler() -> void; diff --git a/arch/x86_64/include/arch/user/main.hpp b/arch/x86_64/include/arch/user/main.hpp index 7127d07..4f1d005 100644 --- a/arch/x86_64/include/arch/user/main.hpp +++ b/arch/x86_64/include/arch/user/main.hpp @@ -7,4 +7,4 @@ namespace teachos::arch::user } // namespace teachos::arch::user -#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index a112924..9539428 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,15 +1,12 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" +#include "arch/context_switching/syscall/syscall_enable.hpp" #include "arch/kernel/cpu/call.hpp" -#include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/user/main.hpp" -#include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching { diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index 9ac63ce..a226e23 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -1,39 +1,8 @@ #include "arch/context_switching/syscall/main.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" -#include "arch/kernel/cpu/msr.hpp" - -#include - namespace teachos::arch::context_switching::syscall { - namespace - { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - - } // namespace - - auto enable_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - - auto syscall(type syscall_number, arguments args) -> uint64_t + auto syscall(type syscall_number, arguments args) -> error { asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -49,7 +18,7 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - uint64_t error{}; + error error{}; asm volatile("mov %%rax, %[output]" : [output] "=m"(error)); return error; } diff --git a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp new file mode 100644 index 0000000..e6265d3 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp @@ -0,0 +1,32 @@ +#include "arch/context_switching/syscall/syscall_enable.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/context_switching/syscall/syscall_handler.hpp" +#include "arch/kernel/cpu/msr.hpp" + +namespace teachos::arch::context_switching::syscall +{ + namespace + { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + + } // namespace + + auto enable_syscall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); + + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 759a092..fbfecc0 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -1,5 +1,6 @@ #include "arch/context_switching/syscall/syscall_handler.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/panic.hpp" #include "arch/video/vga/text.hpp" @@ -8,11 +9,12 @@ namespace teachos::arch::context_switching::syscall namespace { - auto write_to_vga_buffer(uint64_t buffer) + auto write_to_vga_buffer(uint64_t buffer) -> error { video::vga::text::write(reinterpret_cast(buffer), video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); + return error::OK; } } // namespace @@ -38,17 +40,17 @@ namespace teachos::arch::context_switching::syscall // and now. asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); + error result = error::OK; switch (static_cast(syscall_number)) { - case WRITE: - write_to_vga_buffer(arg_0); + case type::WRITE: + result = write_to_vga_buffer(arg_0); break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); break; } - uint64_t result = 0U; asm volatile("mov %[input], %%rax" : /* no output from call */ : [input] "m"(result) @@ -63,6 +65,9 @@ namespace teachos::arch::context_switching::syscall : [input] "m"(rflags) : "memory"); + // Additionally call leave, because x86 allocates tack space for the internal variables. If we do not clean up this + // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the + // method that originally called it, becuase the RIP has not been restored from the previous stack frame. asm volatile("leave\n" "sysretq"); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 6d8eea7..8ce21ba 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -7,7 +7,6 @@ namespace teachos::arch::user { - [[gnu::section(".user_text")]] auto main() -> void { @@ -23,9 +22,9 @@ namespace teachos::arch::user // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto error = context_switching::syscall::syscall(context_switching::syscall::WRITE, - {reinterpret_cast(&syscall_message)}); + char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, + {reinterpret_cast(&syscall_message)}); if (!error) { -- cgit v1.2.3 From 27d4fb90ebbc754e98ff68ce5bc7839a44ed99c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 09:22:28 +0000 Subject: Add comments to syscall components --- .../arch/context_switching/syscall/main.hpp | 47 ++++++++++++++++++---- .../context_switching/syscall/syscall_enable.hpp | 8 ++++ arch/x86_64/src/context_switching/syscall/main.cpp | 2 +- .../context_switching/syscall/syscall_enable.cpp | 4 +- .../context_switching/syscall/syscall_handler.cpp | 2 +- arch/x86_64/src/user/main.cpp | 2 +- 6 files changed, 53 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index ae4c2db..48fa195 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -5,28 +5,61 @@ 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 + 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. }; + /** + * @brief Possible error codes that can be returned by the different syscall methods called depending on the type + * enum. + */ enum class error { OK = 0U, }; + /** + * @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{}; - uint64_t arg_1{}; - uint64_t arg_2{}; - uint64_t arg_3{}; - uint64_t arg_4{}; - uint64_t arg_5{}; + 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 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 Bool-convertable error code converting to true if the syscall failed or false if it didn't. + */ auto syscall(type syscall_number, arguments args = {}) -> error; } // namespace teachos::arch::context_switching::syscall 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 index 59b97b2..8cb468a 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/syscall_enable.hpp @@ -3,6 +3,14 @@ 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 diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index a226e23..93fc613 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -23,4 +23,4 @@ namespace teachos::arch::context_switching::syscall return error; } -} // namespace teachos::arch::context_switching::syscall \ No newline at end of file +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp index e6265d3..3c43336 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp @@ -8,7 +8,7 @@ namespace teachos::arch::context_switching::syscall { namespace { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + interrupt_descriptor_table::segment_selector constexpr KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; auto constexpr IA32_STAR_ADDRESS = 0xC0000081; @@ -29,4 +29,4 @@ namespace teachos::arch::context_switching::syscall kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -} // namespace teachos::arch::context_switching::syscall \ No newline at end of file +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index fbfecc0..da9eb1b 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -72,4 +72,4 @@ namespace teachos::arch::context_switching::syscall "sysretq"); } -} // namespace teachos::arch::context_switching::syscall \ No newline at end of file +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 8ce21ba..1d56d2e 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -32,4 +32,4 @@ namespace teachos::arch::user video::vga::text::common_attributes::green_on_black); } } -} // namespace teachos::arch::user \ No newline at end of file +} // namespace teachos::arch::user -- cgit v1.2.3 From 7d2e8bc16e6c1bacb3c676d21ea2245d8132218f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 11:27:29 +0000 Subject: Remove the addition of USER_ACCESSIBLE flag to every entry created --- .../include/arch/memory/paging/active_page_table.hpp | 2 +- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 16 ++++++++++++---- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 6 ++++++ arch/x86_64/include/arch/memory/paging/page_table.hpp | 3 ++- arch/x86_64/include/arch/user/main.hpp | 5 +++++ arch/x86_64/src/memory/main.cpp | 3 ++- arch/x86_64/src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 10 ++++------ arch/x86_64/src/memory/paging/temporary_page.cpp | 10 +++++----- arch/x86_64/src/user/main.cpp | 12 ------------ 10 files changed, 38 insertions(+), 31 deletions(-) (limited to 'arch') 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 index 9e91a8c..a4a5b64 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -89,7 +89,7 @@ namespace teachos::arch::memory::paging 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); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT | entry::USER_ACCESSIBLE); } /** 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 8d36fde..09e9bf4 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -81,11 +81,12 @@ namespace teachos::arch::memory::paging 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); + active_table[511].set_entry(inactive_table.page_table_level_4_frame, + entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); kernel::cpu::tlb_flush_all(); map_elf_kernel_sections(active_table); - page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); kernel::cpu::tlb_flush_all(); temporary_page.unmap_page(active_table); } @@ -136,7 +137,14 @@ namespace teachos::arch::memory::paging allocator::frame_container::iterator const begin{start_frame}; allocator::frame_container::iterator const end{end_frame}; allocator::frame_container const frames{begin, end}; - entry const entry{section.flags}; + entry entry{section.flags}; + + // TODO: Only set this if we are in the .user_text section. + // address: 0000000000216000, offset: 013000, size: varies depending on code not a a good idea + // Alternatively index Nr. 8 could be used to detect section, can also change if we add more section + entry.set_user_accesible(); + + // TODO: Entering User Mode still works, but then attempting to execute an instruction immedatiately fails. for (auto const & frame : frames) { @@ -146,7 +154,7 @@ namespace teachos::arch::memory::paging 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); + active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE | entry::USER_ACCESSIBLE); } T & allocator; diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index ef4fe61..5cba1bc 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -71,6 +71,12 @@ namespace teachos::arch::memory::paging */ 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_accesible() -> void; + /** * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in * memory. diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 60a0a2f..db7ba6c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -94,7 +94,8 @@ namespace teachos::arch::memory::paging { 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); + this->operator[](table_index) + .set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); // 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"); diff --git a/arch/x86_64/include/arch/user/main.hpp b/arch/x86_64/include/arch/user/main.hpp index 4f1d005..ba30864 100644 --- a/arch/x86_64/include/arch/user/main.hpp +++ b/arch/x86_64/include/arch/user/main.hpp @@ -3,6 +3,11 @@ 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. + */ auto main() -> void; } // namespace teachos::arch::user diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index bd094e0..4cccabb 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -31,7 +31,8 @@ namespace teachos::arch::memory for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, + paging::entry::WRITABLE | paging::entry::USER_ACCESSIBLE); } } } // namespace diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 4e0610e..780f12c 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::memory::paging { auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); temporary_page.unmap_page(active_page_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 3a0f03f..c76c673 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging } // namespace entry::entry(uint64_t flags) - : flags(flags | entry::USER_ACCESSIBLE) // TODO: Temporarily make all entries user accessible + : flags(flags) { // Nothing to do. } @@ -31,15 +31,14 @@ namespace teachos::arch::memory::paging { flags |= entry::EXECUTING_CODE_FORBIDDEN; } - - // TODO: Temporarily make all entries user accessible - flags |= entry::USER_ACCESSIBLE; } auto entry::is_unused() const -> bool { return flags == 0U; } auto entry::set_unused() -> void { flags = 0U; } + auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) @@ -57,8 +56,7 @@ namespace teachos::arch::memory::paging exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - // TODO: Temporarily make all entries user accessible - flags = frame.start_address() | additional_flags.to_ulong() | entry::USER_ACCESSIBLE; + flags = frame.start_address() | additional_flags.to_ulong(); } auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 152241d..9946f36 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -4,21 +4,21 @@ namespace teachos::arch::memory::paging { - auto temporary_page::map_table_frame(allocator::physical_frame frame, - active_page_table & active_table) -> page_table_handle + auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) + -> page_table_handle { page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), page_table_handle::LEVEL1}; return handle; } - auto temporary_page::map_to_frame(allocator::physical_frame frame, - active_page_table & active_table) -> virtual_address + auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table) + -> virtual_address { exception_handling::assert(!active_table.translate_page(page).has_value(), "[Temporary page] Page is already mapped"); - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE | entry::USER_ACCESSIBLE); return page.start_address(); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 1d56d2e..3ddcb32 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -10,18 +10,6 @@ namespace teachos::arch::user [[gnu::section(".user_text")]] auto main() -> void { - // TODO: Remove or replace this wall of text - // RFLAGS is saved into R11, RIP of the next instruction into RCX - // Required for SYSRETURN to know where to return too. - // Additional state needs to be saved by calling convention: - - // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) - // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 - // Not used registers: RBX, RSP, R12, R13, R14 - - // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: - // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); -- cgit v1.2.3 From c9f46f3773e7943ce114af888a44f50061c2ac1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 6 May 2025 13:40:42 +0000 Subject: Remove user Mode Access to VGA / Heap and Kernel Methods. --- .../arch/context_switching/syscall/main.hpp | 1 + .../arch/memory/paging/active_page_table.hpp | 7 +++++-- .../include/arch/memory/paging/kernel_mapper.hpp | 22 ++++++++++++---------- .../include/arch/memory/paging/page_table.hpp | 5 +++-- arch/x86_64/include/arch/user/main.hpp | 1 + .../generic_interrupt_handler.cpp | 1 + arch/x86_64/src/memory/main.cpp | 3 +-- .../src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/temporary_page.cpp | 2 +- arch/x86_64/src/user/main.cpp | 12 +++++++++++- 10 files changed, 37 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index 48fa195..3af5a5a 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -60,6 +60,7 @@ namespace teachos::arch::context_switching::syscall * not function correctly. * @return Bool-convertable error code converting to true if the syscall failed or false if it didn't. */ + [[gnu::section(".user_text")]] auto syscall(type syscall_number, arguments args = {}) -> error; } // namespace teachos::arch::context_switching::syscall 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 index a4a5b64..d77b76c 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -82,14 +82,17 @@ namespace teachos::arch::memory::paging 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)); + // Ignore all bits passed besides the entry::USER_ACCESSIBLE bit, because for the entry into the Level 4 up to + // Level 2 page, we always have to set the entry::PRESENT and entry::WRITABLE bit anyway. + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level), + flags.to_ulong() & entry::USER_ACCESSIBLE); } 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 | entry::USER_ACCESSIBLE); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); } /** 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 09e9bf4..ce74b98 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -81,12 +81,11 @@ namespace teachos::arch::memory::paging 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 | entry::USER_ACCESSIBLE); + 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 | entry::USER_ACCESSIBLE); + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); kernel::cpu::tlb_flush_all(); temporary_page.unmap_page(active_table); } @@ -139,12 +138,15 @@ namespace teachos::arch::memory::paging allocator::frame_container const frames{begin, end}; entry entry{section.flags}; - // TODO: Only set this if we are in the .user_text section. - // address: 0000000000216000, offset: 013000, size: varies depending on code not a a good idea - // Alternatively index Nr. 8 could be used to detect section, can also change if we add more section - entry.set_user_accesible(); - - // TODO: Entering User Mode still works, but then attempting to execute an instruction immedatiately fails. + // TODO: Why exactly are this section required or not required? + // Required to be accesible in User Mode: .user_text (Contains the actuall code executed), .boot_bss (Contains + // statically allocated variables), .boot_rodata (Contains constant data stored in ROM) + // Not required: .text, .rodata, .ctors, .dtors, .bss, .data, .boot_data, .boot_text, .init + if (section.physical_address == 0x100000 || section.physical_address == 0x102000 || + section.physical_address == 0x216000) + { + entry.set_user_accesible(); + } for (auto const & frame : frames) { @@ -154,7 +156,7 @@ namespace teachos::arch::memory::paging 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 | entry::USER_ACCESSIBLE); + active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); } T & allocator; diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index db7ba6c..7b7e29e 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -81,9 +81,10 @@ namespace teachos::arch::memory::paging * @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) -> page_table_handle + 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 @@ -95,7 +96,7 @@ namespace teachos::arch::memory::paging 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 | entry::USER_ACCESSIBLE); + .set_entry(allocated_frame.value(), flags.to_ulong() | 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"); diff --git a/arch/x86_64/include/arch/user/main.hpp b/arch/x86_64/include/arch/user/main.hpp index ba30864..c168a1f 100644 --- a/arch/x86_64/include/arch/user/main.hpp +++ b/arch/x86_64/include/arch/user/main.hpp @@ -8,6 +8,7 @@ namespace teachos::arch::user * 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 diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 8e2c62d..9d061a8 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -8,5 +8,6 @@ namespace teachos::arch::interrupt_handling { (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); } } // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 4cccabb..bd094e0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -31,8 +31,7 @@ namespace teachos::arch::memory for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, - paging::entry::WRITABLE | paging::entry::USER_ACCESSIBLE); + active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); } } } // namespace diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 780f12c..4e0610e 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::memory::paging { auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); temporary_page.unmap_page(active_page_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 9946f36..8e73523 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -18,7 +18,7 @@ namespace teachos::arch::memory::paging exception_handling::assert(!active_table.translate_page(page).has_value(), "[Temporary page] Page is already mapped"); - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE | entry::USER_ACCESSIBLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); return page.start_address(); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 3ddcb32..3e7b0ec 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -3,21 +3,31 @@ #include "arch/context_switching/syscall/main.hpp" // TODO: Disallow this import +#include "arch/kernel/cpu/if.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::user { - [[gnu::section(".user_text")]] auto main() -> void { char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); + kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde + + auto test = new int{20}; // Causes crash Heap is not mapped in User Mode + (void)test; + if (!error) { + // Causes crash vga is not mapped in User Mode video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } + + for (;;) + { + } } } // namespace teachos::arch::user -- cgit v1.2.3 From be32189323ba8c46091d6deaf091cf41147426b4 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 7 May 2025 14:06:25 +0000 Subject: wip custom heap allocation functions for user mode --- .../arch/memory/heap/global_heap_allocator.hpp | 39 +++++++++++++--- .../include/arch/memory/heap/heap_allocator.hpp | 6 ++- .../src/memory/heap/global_heap_allocator.cpp | 54 +++++++++++++++------- arch/x86_64/src/memory/main.cpp | 6 +-- arch/x86_64/src/user/main.cpp | 26 ++++++----- 5 files changed, 92 insertions(+), 39 deletions(-) (limited to 'arch') 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 index 772f171..bfc7b67 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -45,7 +45,7 @@ namespace teachos::arch::memory::heap * @param size Amount of bytes that should be allocated * @return void* Pointer to the start of the allocatable memory area */ - static auto allocate(std::size_t size) -> void *; + static auto kmalloc(std::size_t size) -> void *; /** * @brief Deallocated all memory associated with the memory area starting from the given pointer address. @@ -53,17 +53,44 @@ namespace teachos::arch::memory::heap * * @param pointer Previously allocated memory area, that should now be freed */ - static auto deallocate(void * pointer) noexcept -> void; + 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 * allocator_instance; ///< Instance used to actually allocate and deallocate + static heap_allocator * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory + static 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 furthere execution + * @brief Either returns the previously registered heap allocated or halts further execution * - * @return Reference to the registered heap allocation + * @return Reference to the registered user heap allocation */ - static auto get() -> heap_allocator &; + static auto user() -> heap_allocator &; }; } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp b/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp index 6aed3d8..420a1d3 100644 --- a/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/heap_allocator.hpp @@ -5,8 +5,10 @@ namespace teachos::arch::memory::heap { - std::size_t constexpr HEAP_START = 0x100000000; - std::size_t constexpr HEAP_SIZE = 100 * 1024; + 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 diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index c1ca160..51f6261 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -6,15 +6,20 @@ namespace teachos::arch::memory::heap { - heap_allocator * global_heap_allocator::allocator_instance = nullptr; + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; + heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; - auto global_heap_allocator::allocate(std::size_t size) -> void * { return get().allocate(size); } + auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } - auto global_heap_allocator::deallocate(void * pointer) noexcept -> void { get().deallocate(pointer); } + auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); } + + auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); } + + auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); } auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void { - exception_handling::assert(allocator_instance == nullptr, + exception_handling::assert(kernel_allocator_instance == nullptr, "Calling register_heap_allocator_type can only be done once."); switch (new_type) @@ -23,56 +28,71 @@ namespace teachos::arch::memory::heap // Nothing to do break; case heap_allocator_type::BUMP: { - static bump_allocator allocator{HEAP_START, HEAP_START + HEAP_SIZE}; - allocator_instance = &allocator; + static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + + static bump_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; break; } case heap_allocator_type::LINKED_LIST: { - static linked_list_allocator allocator{HEAP_START, HEAP_START + HEAP_SIZE}; - allocator_instance = &allocator; + static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + + static linked_list_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; break; } } } - auto global_heap_allocator::get() -> heap_allocator & + auto global_heap_allocator::kernel() -> heap_allocator & + { + exception_handling::assert(kernel_allocator_instance != nullptr, + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."); + + return *kernel_allocator_instance; + } + + auto global_heap_allocator::user() -> heap_allocator & { - exception_handling::assert(allocator_instance != nullptr, + exception_handling::assert(user_allocator_instance != nullptr, "Attempted to allocate or deallocate using the global_heap_allocator before " "register_heap_allocation_type was called."); - return *allocator_instance; + return *user_allocator_instance; } } // namespace teachos::arch::memory::heap auto operator new(std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::allocate(size); + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); } auto operator delete(void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator delete(void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator new[](std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::allocate(size); + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); } auto operator delete[](void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator delete[](void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index bd094e0..558fbce 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -5,7 +5,7 @@ #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/heap/heap_allocator.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -22,9 +22,9 @@ namespace teachos::arch::memory template auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { - auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); + auto const start_page = paging::virtual_page::containing_address(heap::KERNEL_HEAP_START); auto const end_page = - ++(paging::virtual_page::containing_address(memory::heap::HEAP_START + memory::heap::HEAP_SIZE - 1)); + ++(paging::virtual_page::containing_address(heap::KERNEL_HEAP_START + heap::KERNEL_HEAP_SIZE - 1)); paging::page_container::iterator const begin{start_page}; paging::page_container::iterator const end{end_page}; paging::page_container const pages{begin, end}; diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 3e7b0ec..4f6e688 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -1,8 +1,9 @@ #include "arch/user/main.hpp" #include "arch/context_switching/syscall/main.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" -// TODO: Disallow this import +// TODO: Disallow these imports #include "arch/kernel/cpu/if.hpp" #include "arch/video/vga/text.hpp" @@ -11,20 +12,23 @@ namespace teachos::arch::user auto main() -> void { char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, - {reinterpret_cast(&syscall_message)}); + context_switching::syscall::syscall(context_switching::syscall::type::WRITE, + {reinterpret_cast(&syscall_message)}); - kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde + // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde - auto test = new int{20}; // Causes crash Heap is not mapped in User Mode + auto test = memory::heap::global_heap_allocator::malloc(20U); (void)test; - if (!error) - { - // Causes crash vga is not mapped in User Mode - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } + // auto test = new int{20}; // Causes crash Heap is not mapped in User Mode + // (void)test; + + // if (!error) + // { + // // Causes crash vga is not mapped in User Mode + // video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + // video::vga::text::common_attributes::green_on_black); + // } for (;;) { -- cgit v1.2.3 From 0b62fdb3fe657d056a42d7567b67951ba3468738 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 8 May 2025 08:51:52 +0000 Subject: wip allocating heap memory in user mode --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/heap/global_heap_allocator.hpp | 7 ++- .../arch/memory/heap/user_heap_allocator.hpp | 48 +++++++++++++++++++ .../include/arch/memory/paging/kernel_mapper.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 3 ++ .../src/memory/heap/global_heap_allocator.cpp | 20 ++++---- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 55 ++++++++++++++++++++++ arch/x86_64/src/memory/main.cpp | 18 ++++--- arch/x86_64/src/user/main.cpp | 4 +- 9 files changed, 136 insertions(+), 22 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp create mode 100644 arch/x86_64/src/memory/heap/user_heap_allocator.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 3d6d2c7..0a6ab9c 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -64,6 +64,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" "src/memory/heap/bump_allocator.cpp" + "src/memory/heap/user_heap_allocator.cpp" "src/memory/heap/memory_block.cpp" "src/memory/heap/linked_list_allocator.cpp" "src/memory/heap/global_heap_allocator.cpp" 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 index bfc7b67..d0d1080 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -2,6 +2,7 @@ #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 { @@ -76,7 +77,8 @@ namespace teachos::arch::memory::heap private: static heap_allocator * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory - static heap_allocator * user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory + 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 @@ -90,7 +92,8 @@ namespace teachos::arch::memory::heap * * @return Reference to the registered user heap allocation */ - static auto user() -> heap_allocator &; + [[gnu::section(".user_text")]] + static auto user() -> user_heap_allocator &; }; } // 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 new file mode 100644 index 0000000..1dab047 --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp @@ -0,0 +1,48 @@ +#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/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 user_heap_allocator + { + /** + * @brief Constructor. + * + * @param heap_start Start of the allocatable heap area + * @param heap_end End of the allocatable heap area (Start + Size) + */ + user_heap_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 *; + + /** + * @copybrief heap_allocator::deallocate + * + * @note Simply does nothing, because this allocator leaks all memory + */ + auto deallocate(void * pointer) noexcept -> void; + + 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_USER_HEAP_ALLOCATOR_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 index ce74b98..6459107 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -143,7 +143,7 @@ namespace teachos::arch::memory::paging // statically allocated variables), .boot_rodata (Contains constant data stored in ROM) // Not required: .text, .rodata, .ctors, .dtors, .bss, .data, .boot_data, .boot_text, .init if (section.physical_address == 0x100000 || section.physical_address == 0x102000 || - section.physical_address == 0x216000) + section.physical_address == 0x217000) { entry.set_user_accesible(); } diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 05c879e..43b5f90 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,6 +63,9 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); // heap_test(); + auto address = memory::heap::global_heap_allocator::kmalloc(8U); + (void)address; + context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index 51f6261..acba02d 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -3,11 +3,12 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/linked_list_allocator.hpp" +#include "arch/memory/heap/user_heap_allocator.hpp" namespace teachos::arch::memory::heap { heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; - heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; + user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } @@ -30,20 +31,17 @@ namespace teachos::arch::memory::heap case heap_allocator_type::BUMP: { static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; - - static bump_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; - user_allocator_instance = &user_allocator; break; } case heap_allocator_type::LINKED_LIST: { static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; - - static linked_list_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; - user_allocator_instance = &user_allocator; break; } } + + static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; } auto global_heap_allocator::kernel() -> heap_allocator & @@ -55,11 +53,11 @@ namespace teachos::arch::memory::heap return *kernel_allocator_instance; } - auto global_heap_allocator::user() -> heap_allocator & + auto global_heap_allocator::user() -> user_heap_allocator & { - exception_handling::assert(user_allocator_instance != nullptr, - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."); + // exception_handling::assert(user_allocator_instance != nullptr, + // "Attempted to allocate or deallocate using the global_heap_allocator before " + // "register_heap_allocation_type was called."); return *user_allocator_instance; } diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp new file mode 100644 index 0000000..f09811d --- /dev/null +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -0,0 +1,55 @@ +#include "arch/memory/heap/user_heap_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include + +namespace teachos::arch::memory::heap +{ + namespace + { + template + [[gnu::section(".user_text")]] + auto saturating_add(T x, T y) -> T + requires std::is_unsigned_v + { + if (x > std::numeric_limits::max() - y) + { + return std::numeric_limits::max(); + } + T result = x + y; + return result; + } + } // namespace + + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); + // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time + // causing the value to differ and the calculation to have to be redone. + for (;;) + { + auto const alloc_end = saturating_add(alloc_start, size); + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); + // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another + // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation + // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. + auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); + if (updated) + { + return reinterpret_cast(alloc_start); + } + } + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + { + if (pointer) + { + } + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 558fbce..4cdfa80 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -20,18 +20,23 @@ namespace teachos::arch::memory } template - auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void + auto remap_heap(T & allocator, paging::active_page_table & active_table, bool is_user_heap = false) -> void { - auto const start_page = paging::virtual_page::containing_address(heap::KERNEL_HEAP_START); - auto const end_page = - ++(paging::virtual_page::containing_address(heap::KERNEL_HEAP_START + heap::KERNEL_HEAP_SIZE - 1)); + auto const heap_start = is_user_heap ? heap::USER_HEAP_START : heap::KERNEL_HEAP_START; + auto const heap_size = is_user_heap ? heap::USER_HEAP_SIZE : heap::KERNEL_HEAP_SIZE; + + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); paging::page_container::iterator const begin{start_page}; paging::page_container::iterator const end{end_page}; paging::page_container const pages{begin, end}; + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = is_user_heap ? base_flags | paging::entry::USER_ACCESSIBLE : base_flags; + for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, flags); } } } // namespace @@ -54,7 +59,8 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - remap_heap(allocator, active_table); + remap_heap(allocator, active_table); // Remap kernel heap + remap_heap(allocator, active_table, true); // Remap user heap video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 4f6e688..59647f8 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -17,8 +17,8 @@ namespace teachos::arch::user // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde - auto test = memory::heap::global_heap_allocator::malloc(20U); - (void)test; + auto address = memory::heap::global_heap_allocator::malloc(8U); + (void)address; // auto test = new int{20}; // Causes crash Heap is not mapped in User Mode // (void)test; -- cgit v1.2.3 From d7205b75cda2caff078cea26ff1508f9daa5b4cc Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 8 May 2025 12:34:57 +0000 Subject: make user_allocator_instance be part of user_data section --- arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') 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 index d0d1080..6fcab6f 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -77,7 +77,7 @@ namespace teachos::arch::memory::heap private: static heap_allocator * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory - static user_heap_allocator * + [[gnu::section(".user_data")]] static user_heap_allocator * user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory /** -- cgit v1.2.3 From d80ecf29baada6242c5181adaec0d1500707cad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 9 May 2025 12:00:23 +0000 Subject: Move necessary code into user text --- arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp | 3 ++- arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp | 2 ++ arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 8 +++++--- arch/x86_64/scripts/kernel.ld | 5 +++++ arch/x86_64/src/memory/heap/global_heap_allocator.cpp | 3 +++ arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 5 ++++- 6 files changed, 21 insertions(+), 5 deletions(-) (limited to 'arch') 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 index 6fcab6f..b20a452 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -77,7 +77,8 @@ namespace teachos::arch::memory::heap private: static heap_allocator * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory - [[gnu::section(".user_data")]] static user_heap_allocator * + [[gnu::section(".user_data")]] + static user_heap_allocator * user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory /** 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 1dab047..9d00c19 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 @@ -28,6 +28,7 @@ namespace teachos::arch::memory::heap // Nothing to do } + [[gnu::section(".user_text")]] auto allocate(std::size_t size) -> void *; /** @@ -35,6 +36,7 @@ namespace teachos::arch::memory::heap * * @note Simply does nothing, because this allocator leaks all memory */ + [[gnu::section(".user_text")]] auto deallocate(void * pointer) noexcept -> void; private: 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 6459107..95d04f4 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -139,11 +139,13 @@ namespace teachos::arch::memory::paging entry entry{section.flags}; // TODO: Why exactly are this section required or not required? - // Required to be accesible in User Mode: .user_text (Contains the actuall code executed), .boot_bss (Contains - // statically allocated variables), .boot_rodata (Contains constant data stored in ROM) + // Required to be accesible in User Mode: .user_text (Contains the actual code executed), .boot_bss (Contains + // statically allocated variables), .boot_rodata (Contains constant data stored in ROM), .user_data (Contains + // static user variables // Not required: .text, .rodata, .ctors, .dtors, .bss, .data, .boot_data, .boot_text, .init if (section.physical_address == 0x100000 || section.physical_address == 0x102000 || - section.physical_address == 0x217000) + section.physical_address == 0x217000 || section.physical_address == 0x21D000 || + section.physical_address == 0x209000) { entry.set_user_accesible(); } diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 239d026..88d90fe 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -128,6 +128,11 @@ SECTIONS *(.data*) } + .user_data ALIGN(4K) : AT (ADDR (.user_data)) + { + *(.user_data*) + } + /*************************************************************************** * In accordance with the symbol definitions at the start, we generate some * symbols to mark the end of our loaded image. diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index acba02d..23e2458 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -40,6 +40,7 @@ namespace teachos::arch::memory::heap } } + [[gnu::section(".user_data")]] static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; user_allocator_instance = &user_allocator; } @@ -55,6 +56,8 @@ namespace teachos::arch::memory::heap auto global_heap_allocator::user() -> user_heap_allocator & { + // TODO: Assert Method does not exist in .user_text meaning this causes a Page Fault when accessed, Make it into a + // syscall instead // exception_handling::assert(user_allocator_instance != nullptr, // "Attempted to allocate or deallocate using the global_heap_allocator before " // "register_heap_allocation_type was called."); diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index f09811d..eefcab5 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -25,7 +25,10 @@ namespace teachos::arch::memory::heap auto user_heap_allocator::allocate(std::size_t size) -> void * { - // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // TODO: .load() crashes because it is only in the kernel .text section and not the user one? How would you fix + // Similarly assert cause a crash here it is easier though simply create a syscall for the assert method. + + // that? Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the // exchange failed, becuase the value was not the expected one. auto alloc_start = next.load(std::memory_order::relaxed); // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time -- cgit v1.2.3 From a5812be4fa8ecc208219682204b14969d7b718b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 9 May 2025 13:15:58 +0000 Subject: Switch uer heap to linked list allocator --- .../arch/memory/heap/user_heap_allocator.hpp | 118 ++++++++++--- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 186 +++++++++++++++++---- 2 files changed, 251 insertions(+), 53 deletions(-) (limited to 'arch') 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 9d00c19..d698888 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 @@ -1,16 +1,14 @@ #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/heap_allocator.hpp" - -#include -#include +#include "arch/memory/heap/memory_block.hpp" +#include "arch/stl/mutex.hpp" namespace teachos::arch::memory::heap { /** - * @brief Simple heap allocator, which allocates linearly and leaks all allocated memory, because it does not really - * deallocate anything. + * @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 { @@ -20,31 +18,109 @@ namespace teachos::arch::memory::heap * @param heap_start Start of the allocatable heap area * @param heap_end End of the allocatable heap area (Start + Size) */ - user_heap_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 - } + user_heap_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. + */ [[gnu::section(".user_text")]] auto allocate(std::size_t size) -> void *; + [[gnu::section(".user_text")]] + auto deallocate(void * pointer) noexcept -> void; + + private: /** - * @copybrief heap_allocator::deallocate + * @brief Returns the smallest allocatable block of heap memory. * - * @note Simply does nothing, because this allocator leaks all 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 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 deallocate(void * pointer) noexcept -> void; + auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void *; - 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 - }; + /** + * @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; + + std::size_t heap_start; ///< Start of the allocatable heap area. + std::size_t heap_end; ///< End of the allocatable heap area. + memory_block * first; ///< First free entry in our memory. + stl::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/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index eefcab5..6843d66 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,58 +1,180 @@ #include "arch/memory/heap/user_heap_allocator.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" -#include -#include +#include namespace teachos::arch::memory::heap { - namespace + user_heap_allocator::user_heap_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start(heap_start) + , heap_end(heap_end) + , first(nullptr) + , mutex{stl::mutex{}} { - template - [[gnu::section(".user_text")]] - auto saturating_add(T x, T y) -> T - requires std::is_unsigned_v + auto const heap_size = heap_end - heap_start; + exception_handling::assert( + heap_size > min_allocatable_size(), + "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " + "atleast one memory hole entry"); + first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) { - if (x > std::numeric_limits::max() - y) + // TODO: Can not access current pointer. Results in a General Protection Fault? + if (current->size == total_size) { - return std::numeric_limits::max(); + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); } - T result = x + y; - return result; + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + + previous = current; + current = current->next; } - } // namespace - auto user_heap_allocator::allocate(std::size_t size) -> void * + exception_handling::panic("[Linked List Allocator] Out of memory"); + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void { - // TODO: .load() crashes because it is only in the kernel .text section and not the user one? How would you fix - // Similarly assert cause a crash here it is easier though simply create a syscall for the assert method. - - // that? Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the - // exchange failed, becuase the value was not the expected one. - auto alloc_start = next.load(std::memory_order::relaxed); - // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time - // causing the value to differ and the calculation to have to be redone. - for (;;) + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) { - auto const alloc_end = saturating_add(alloc_start, size); - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); - // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another - // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation - // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. - auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); - if (updated) + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) { - return reinterpret_cast(alloc_start); + break; } + + previous = current; + current = current->next; } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); } - auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * { - if (pointer) + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean + // that the block has already been deallocated and we therefore attempted a double free. + exception_handling::assert(previous_block == nullptr || + start_address >= + (reinterpret_cast(previous_block) + previous_block->size), + "[Linked List Allocator] Attempted double free detected"); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) { + first = new_block; + return; } + previous_block->next = new_block; } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From f3a976be198d97573b630242c0f833c290c62d81 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 10 May 2025 10:33:26 +0000 Subject: experiment with globally available linker sections and page table entry flags --- .../arch/memory/heap/global_heap_allocator.hpp | 3 +- .../include/arch/memory/paging/kernel_mapper.hpp | 27 +++-- .../include/arch/memory/paging/page_entry.hpp | 2 + arch/x86_64/include/arch/stl/container.hpp | 24 +++- .../arch/stl/contiguous_pointer_iterator.hpp | 34 +++++- .../include/arch/stl/forward_value_iterator.hpp | 15 ++- arch/x86_64/include/arch/stl/mutex.hpp | 3 + arch/x86_64/include/arch/stl/shared_pointer.hpp | 40 ++++++- arch/x86_64/include/arch/stl/stack.hpp | 42 ++++++- arch/x86_64/include/arch/stl/unique_pointer.hpp | 37 +++++- arch/x86_64/include/arch/stl/vector.hpp | 126 +++++++++++++++++---- arch/x86_64/scripts/kernel.ld | 5 + arch/x86_64/src/memory/paging/page_entry.cpp | 2 + 13 files changed, 305 insertions(+), 55 deletions(-) (limited to 'arch') 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 index b20a452..6fcab6f 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -77,8 +77,7 @@ namespace teachos::arch::memory::heap private: static heap_allocator * kernel_allocator_instance; ///< Instance used to allocate and deallocate kernel heap memory - [[gnu::section(".user_data")]] - static user_heap_allocator * + [[gnu::section(".user_data")]] static user_heap_allocator * user_allocator_instance; ///< Instance used to allocate and deallocate user heap memory /** 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 95d04f4..05fde8b 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -40,6 +40,10 @@ namespace teachos::arch::memory::paging */ auto remap_kernel() -> active_page_table & { + // 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}; auto & active_table = active_page_table::create_or_get(); auto const frame = allocator.allocate_frame(); @@ -138,14 +142,21 @@ namespace teachos::arch::memory::paging allocator::frame_container const frames{begin, end}; entry entry{section.flags}; - // TODO: Why exactly are this section required or not required? - // Required to be accesible in User Mode: .user_text (Contains the actual code executed), .boot_bss (Contains - // statically allocated variables), .boot_rodata (Contains constant data stored in ROM), .user_data (Contains - // static user variables - // Not required: .text, .rodata, .ctors, .dtors, .bss, .data, .boot_data, .boot_text, .init - if (section.physical_address == 0x100000 || section.physical_address == 0x102000 || - section.physical_address == 0x217000 || section.physical_address == 0x21D000 || - section.physical_address == 0x209000) + // Required to be accesible in User Mode: + // - .user_text (Contains the actual code executed) + // - .boot_bss (Contains statically allocated variables) + // - .boot_rodata (Contains constant data stored in ROM) + // - .user_data (Contains static user variables) + if (section.physical_address == 0x100000 /* .boot_rodata */ || + section.physical_address == 0x102000 /* .boot_bss */ || + section.physical_address == 0x218000 /* .stl_text */) + { + entry.set_user_accesible(); + entry.set_global(); + } + + if (section.physical_address == 0x217000 /* .user_text */ || + section.physical_address == 0x21D000 /* .user_data */) { entry.set_user_accesible(); } diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 5cba1bc..6ee1a13 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -77,6 +77,8 @@ namespace teachos::arch::memory::paging */ auto set_user_accesible() -> void; + auto set_global() -> void; + /** * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in * memory. diff --git a/arch/x86_64/include/arch/stl/container.hpp b/arch/x86_64/include/arch/stl/container.hpp index b0f513b..4ea08c7 100644 --- a/arch/x86_64/include/arch/stl/container.hpp +++ b/arch/x86_64/include/arch/stl/container.hpp @@ -48,7 +48,11 @@ namespace teachos::arch::stl * * @return Iterator pointing to first element of the memory area. */ - auto begin() const -> iterator { return begin_itr; } + [[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. @@ -56,7 +60,11 @@ namespace teachos::arch::stl * * @return Iterator pointing to one past the last element of the memory area. */ - auto end() const -> iterator { return end_itr; } + [[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 @@ -64,14 +72,22 @@ namespace teachos::arch::stl * * @return Actual size of this container. */ - auto size() const -> size_type { return std::distance(begin(), end()); } + [[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 */ - auto empty() const -> bool { return size() == 0; } + [[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. diff --git a/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp b/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp index d15d2e2..f2dfb2b 100644 --- a/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp +++ b/arch/x86_64/include/arch/stl/contiguous_pointer_iterator.hpp @@ -45,20 +45,29 @@ namespace teachos::arch::stl * * @return Reference to the value. */ - auto operator*() const -> reference_type { return *ptr; } + [[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. */ - auto operator->() const -> pointer_type { return ptr; } + [[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; @@ -71,6 +80,7 @@ namespace teachos::arch::stl * * @return Reference to the incremented underlying address. */ + [[gnu::section(".stl_text")]] auto operator++() -> contiguous_pointer_iterator & { ++ptr; @@ -82,6 +92,7 @@ namespace teachos::arch::stl * * @return Copy of the decremented underlying address. */ + [[gnu::section(".stl_text")]] auto operator--(int) -> contiguous_pointer_iterator { auto const old_value = *this; @@ -94,6 +105,7 @@ namespace teachos::arch::stl * * @return Copy of the incremented underlying address. */ + [[gnu::section(".stl_text")]] auto operator++(int) -> contiguous_pointer_iterator { auto const old_value = *this; @@ -107,6 +119,7 @@ namespace teachos::arch::stl * @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; @@ -119,6 +132,7 @@ namespace teachos::arch::stl * @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; @@ -131,6 +145,7 @@ namespace teachos::arch::stl * @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}; @@ -142,6 +157,7 @@ namespace teachos::arch::stl * @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}; @@ -153,7 +169,11 @@ namespace teachos::arch::stl * @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. */ - auto operator-(const contiguous_pointer_iterator & other) const -> difference_type { return ptr - other.ptr; } + [[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 @@ -162,7 +182,11 @@ namespace teachos::arch::stl * @param index Index we want to access and get the value from. * @return Reference to the value at the given index. */ - auto operator[](difference_type index) const -> value_type & { return *(ptr + 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. @@ -170,6 +194,7 @@ namespace teachos::arch::stl * @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; /** @@ -178,6 +203,7 @@ namespace teachos::arch::stl * @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: diff --git a/arch/x86_64/include/arch/stl/forward_value_iterator.hpp b/arch/x86_64/include/arch/stl/forward_value_iterator.hpp index 7c30964..be3d8e6 100644 --- a/arch/x86_64/include/arch/stl/forward_value_iterator.hpp +++ b/arch/x86_64/include/arch/stl/forward_value_iterator.hpp @@ -60,20 +60,29 @@ namespace teachos::arch::stl * * @return Reference to the value. */ - auto operator*() const -> const_reference_type { return 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. */ - auto operator->() const -> const_pointer_type { return &value; } + [[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; @@ -85,6 +94,7 @@ namespace teachos::arch::stl * * @return Copy of the incremented underlying value. */ + [[gnu::section(".stl_text")]] auto operator++(int) -> forward_value_iterator { auto const old_value = *this; @@ -98,6 +108,7 @@ namespace teachos::arch::stl * @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: diff --git a/arch/x86_64/include/arch/stl/mutex.hpp b/arch/x86_64/include/arch/stl/mutex.hpp index d8fd9dc..a7d297d 100644 --- a/arch/x86_64/include/arch/stl/mutex.hpp +++ b/arch/x86_64/include/arch/stl/mutex.hpp @@ -34,6 +34,7 @@ namespace teachos::arch::stl /** * @brief Lock the mutex (blocks for as long as it is not available). */ + [[gnu::section(".stl_text")]] auto lock() -> void; /** @@ -41,11 +42,13 @@ namespace teachos::arch::stl * * @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: diff --git a/arch/x86_64/include/arch/stl/shared_pointer.hpp b/arch/x86_64/include/arch/stl/shared_pointer.hpp index 1ddc182..c9796a8 100644 --- a/arch/x86_64/include/arch/stl/shared_pointer.hpp +++ b/arch/x86_64/include/arch/stl/shared_pointer.hpp @@ -25,6 +25,7 @@ namespace teachos::arch::stl * * @param pointer A pointer to an object to manage (default is nullptr). */ + [[gnu::section(".stl_text")]] explicit shared_pointer(T * pointer = nullptr) : pointer(pointer) , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) @@ -37,6 +38,7 @@ namespace teachos::arch::stl * * @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) @@ -52,6 +54,7 @@ namespace teachos::arch::stl * * @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) @@ -68,6 +71,7 @@ namespace teachos::arch::stl * @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) @@ -92,6 +96,7 @@ namespace teachos::arch::stl * @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) @@ -109,13 +114,18 @@ namespace teachos::arch::stl /** * @brief Destructor. Cleans up resources if necessary. */ - ~shared_pointer() { cleanup(); } + [[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(); @@ -129,6 +139,7 @@ namespace teachos::arch::stl * * @param other The shared_pointer to swap with. */ + [[gnu::section(".stl_text")]] void swap(shared_pointer & other) { std::swap(pointer, other.pointer); @@ -140,21 +151,33 @@ namespace teachos::arch::stl * * @return Returns the object owned by *this, equivalent to *get(). */ - auto operator*() const -> T & { return *pointer; } + [[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(). */ - auto operator->() const -> T * { return pointer; } + [[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. */ - auto get() const -> T * { return pointer; } + [[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 @@ -167,6 +190,7 @@ namespace teachos::arch::stl * @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) @@ -182,17 +206,23 @@ namespace teachos::arch::stl * * @return true if *this owns an object, false otherwise. */ - explicit operator bool() const { return pointer != nullptr; } + [[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) diff --git a/arch/x86_64/include/arch/stl/stack.hpp b/arch/x86_64/include/arch/stl/stack.hpp index 9ecf0ca..48bcf10 100644 --- a/arch/x86_64/include/arch/stl/stack.hpp +++ b/arch/x86_64/include/arch/stl/stack.hpp @@ -35,6 +35,7 @@ namespace teachos::arch::stl * @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) { @@ -49,6 +50,7 @@ namespace teachos::arch::stl * @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) { @@ -60,6 +62,7 @@ namespace teachos::arch::stl * * @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) { @@ -74,6 +77,7 @@ namespace teachos::arch::stl * * @param other Other instance of stack we want to copy the data from. */ + [[gnu::section(".stl_text")]] stack(stack const & other) : _container(other) { @@ -89,7 +93,11 @@ namespace teachos::arch::stl * @param other Other instance of vector we want to copy the data from. * @return Newly created copy. */ - stack & operator=(stack const & other) { _container = other; } + [[gnu::section(".stl_text")]] + stack & operator=(stack const & other) + { + _container = other; + } /** * @brief Destructor. @@ -102,7 +110,11 @@ namespace teachos::arch::stl * * @return Current amount of elements. */ - auto size() const -> size_type { return _container.size(); } + [[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 @@ -110,7 +122,11 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - auto top() -> reference { return _container.back(); } + [[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 @@ -118,7 +134,11 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ - auto top() const -> const_reference { return _container.back(); } + [[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 @@ -133,6 +153,7 @@ namespace teachos::arch::stl * @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)); @@ -152,6 +173,7 @@ namespace teachos::arch::stl * @return value_type& */ template + [[gnu::section(".stl_text")]] auto emplace(Args &&... args) -> reference { _container.emplace_back(std::forward(args)...); @@ -164,14 +186,22 @@ namespace teachos::arch::stl * further execution. Iterators and references to the last element are invalidated. The end() * iterator is also invalidated. */ - auto pop() -> void { _container.pop_back(); } + [[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. */ - auto empty() const -> bool { return _container.empty(); } + [[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. diff --git a/arch/x86_64/include/arch/stl/unique_pointer.hpp b/arch/x86_64/include/arch/stl/unique_pointer.hpp index 899a35b..03b4ef3 100644 --- a/arch/x86_64/include/arch/stl/unique_pointer.hpp +++ b/arch/x86_64/include/arch/stl/unique_pointer.hpp @@ -17,6 +17,7 @@ namespace teachos::arch::stl * * @param ptr A pointer to an object to manage (default is nullptr). */ + [[gnu::section(".stl_text")]] explicit unique_pointer(T * ptr = nullptr) : pointer(ptr) { @@ -26,7 +27,11 @@ namespace teachos::arch::stl /** * @brief Destructor that deletes the managed object. */ - ~unique_pointer() { delete pointer; } + [[gnu::section(".stl_text")]] + ~unique_pointer() + { + delete pointer; + } /** * @brief Deleted copy constructor to enforce unique ownership. @@ -43,6 +48,7 @@ namespace teachos::arch::stl * * @param other Unique pointer to move from. */ + [[gnu::section(".stl_text")]] unique_pointer(unique_pointer && other) noexcept : pointer(other.pointer) { @@ -55,6 +61,7 @@ namespace teachos::arch::stl * @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) @@ -71,28 +78,44 @@ namespace teachos::arch::stl * * @return Returns the object owned by *this, equivalent to *get(). */ - auto operator*() const -> T & { return *pointer; } + [[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(). */ - auto operator->() const -> T * { return pointer; } + [[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. */ - auto get() const -> T * { return pointer; } + [[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. */ - explicit operator bool() const noexcept { return pointer != nullptr; } + [[gnu::section(".stl_text")]] + explicit operator bool() const noexcept + { + return pointer != nullptr; + } /** * @brief Releases the ownership of the managed object, if any. @@ -102,6 +125,7 @@ namespace teachos::arch::stl * @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; @@ -118,6 +142,7 @@ namespace teachos::arch::stl * * @param ptr Pointer to a new object to manage (default = nullptr). */ + [[gnu::section(".stl_text")]] auto reset(T * ptr = nullptr) -> void { delete pointer; @@ -129,6 +154,7 @@ namespace teachos::arch::stl * * @param other Another unique_ptr object to swap the managed object and the deleter with. */ + [[gnu::section(".stl_text")]] auto swap(unique_pointer & other) -> void { using std::swap; @@ -138,6 +164,7 @@ namespace teachos::arch::stl /** * @brief Defaulted three-way comparator operator. */ + [[gnu::section(".stl_text")]] auto operator<=>(const unique_pointer & other) const = default; private: diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp index c7d7853..5314029 100644 --- a/arch/x86_64/include/arch/stl/vector.hpp +++ b/arch/x86_64/include/arch/stl/vector.hpp @@ -101,6 +101,7 @@ namespace teachos::arch::stl * @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; @@ -122,7 +123,11 @@ namespace teachos::arch::stl * * @return Current amount of elements. */ - auto size() const -> size_type { return _size; } + [[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 @@ -130,7 +135,11 @@ namespace teachos::arch::stl * * @return Current amount of space the vector has for elements. */ - auto capacity() const -> size_type { return _capacity; } + [[gnu::section(".stl_text")]] + auto capacity() const -> size_type + { + return _capacity; + } /** * @brief Array indexing operator. Allowing to access element at the given index. @@ -140,7 +149,11 @@ namespace teachos::arch::stl * @param index Index we want to access elements at. * @return Reference to the underlying element. */ - auto operator[](size_type index) -> reference { return _data[index]; } + [[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. @@ -150,7 +163,11 @@ namespace teachos::arch::stl * @param index Index we want to access elements at. * @return Reference to the underlying element. */ - auto operator[](size_type index) const -> const_reference { return _data[index]; } + [[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. @@ -160,6 +177,7 @@ namespace teachos::arch::stl * @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); @@ -174,6 +192,7 @@ namespace teachos::arch::stl * @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); @@ -193,6 +212,7 @@ namespace teachos::arch::stl * @param value The value of the element to append. */ template + [[gnu::section(".stl_text")]] auto push_back(U && value) -> void { increase_capacity_if_full(); @@ -214,6 +234,7 @@ namespace teachos::arch::stl * @return value_type& */ template + [[gnu::section(".stl_text")]] auto emplace_back(Args &&... args) -> value_type & { increase_capacity_if_full(); @@ -227,6 +248,7 @@ namespace teachos::arch::stl * 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(); @@ -239,7 +261,11 @@ namespace teachos::arch::stl * * @return Iterator to the first element. */ - auto begin() noexcept -> pointer { return _data; } + [[gnu::section(".stl_text")]] + auto begin() noexcept -> pointer + { + return _data; + } /** * @brief Returns an iterator to the first element of the vector. @@ -247,7 +273,11 @@ namespace teachos::arch::stl * * @return Iterator to the first element. */ - auto begin() const noexcept -> const_pointer { return _data; } + [[gnu::section(".stl_text")]] + auto begin() const noexcept -> const_pointer + { + return _data; + } /** * @brief Returns an iterator to the first element of the vector. @@ -255,7 +285,11 @@ namespace teachos::arch::stl * * @return Iterator to the first element. */ - auto cbegin() const noexcept -> const_pointer { return begin(); } + [[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 @@ -263,7 +297,11 @@ namespace teachos::arch::stl * * @return Reverse iterator to the first element. */ - auto rbegin() noexcept -> pointer { return _data + _size - 1; } + [[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 @@ -271,7 +309,11 @@ namespace teachos::arch::stl * * @return Reverse iterator to the first element. */ - auto rbegin() const noexcept -> const_pointer { return _data + _size - 1; } + [[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 @@ -279,7 +321,11 @@ namespace teachos::arch::stl * * @return Reverse iterator to the first element. */ - auto crbegin() const noexcept -> const_pointer { return rbegin(); } + [[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 @@ -287,7 +333,11 @@ namespace teachos::arch::stl * * @return Iterator to the element following the last element. */ - auto end() noexcept -> pointer { return _data + _size; } + [[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 @@ -295,7 +345,11 @@ namespace teachos::arch::stl * * @return Iterator to the element following the last element. */ - auto end() const noexcept -> const_pointer { return _data + _size; } + [[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 @@ -303,7 +357,11 @@ namespace teachos::arch::stl * * @return Iterator to the element following the last element. */ - auto cend() const noexcept -> const_pointer { return end(); } + [[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 @@ -312,7 +370,11 @@ namespace teachos::arch::stl * * @return Reverse iterator to the element following the last element. */ - auto rend() noexcept -> pointer { return _data + size - 1; } + [[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 @@ -321,7 +383,11 @@ namespace teachos::arch::stl * * @return Reverse iterator to the element following the last element. */ - auto rend() const noexcept -> const_pointer { return _data + size - 1; } + [[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 @@ -330,7 +396,11 @@ namespace teachos::arch::stl * * @return Reverse iterator to the element following the last element. */ - auto crend() const noexcept -> const_pointer { return rbegin(); } + [[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 @@ -340,7 +410,11 @@ namespace teachos::arch::stl * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal * to the address of the first element. */ - auto data() -> pointer { return _data; } + [[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 @@ -350,7 +424,11 @@ namespace teachos::arch::stl * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal * to the address of the first element. */ - auto data() const -> const_pointer { return _data; } + [[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 @@ -358,6 +436,7 @@ namespace teachos::arch::stl * * @return Reference to the first element. */ + [[gnu::section(".stl_text")]] auto front() -> reference { throw_if_empty(); @@ -370,6 +449,7 @@ namespace teachos::arch::stl * * @return Reference to the first element. */ + [[gnu::section(".stl_text")]] auto front() const -> const_reference { throw_if_empty(); @@ -382,6 +462,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ + [[gnu::section(".stl_text")]] auto back() -> reference { throw_if_empty(); @@ -394,6 +475,7 @@ namespace teachos::arch::stl * * @return Reference to the last element. */ + [[gnu::section(".stl_text")]] auto back() const -> const_reference { throw_if_empty(); @@ -427,6 +509,7 @@ namespace teachos::arch::stl * * @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) @@ -448,6 +531,7 @@ namespace teachos::arch::stl * 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) @@ -468,7 +552,11 @@ namespace teachos::arch::stl * * @return True if there are no elements, false if there are. */ - auto empty() const -> bool { return _size <= 0; } + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _size <= 0; + } private: /** diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 88d90fe..1856123 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -95,6 +95,11 @@ SECTIONS *(.user_text) } + .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) + { + *(.stl_text) + } + .rodata ALIGN(4K) : AT (ADDR (.rodata)) { *(.rodata) diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index c76c673..57e33f7 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -39,6 +39,8 @@ namespace teachos::arch::memory::paging auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_global() -> void { flags |= entry::GLOBAL; } + auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) -- cgit v1.2.3 From c4261dd2312f8c55dc795f2674a03d6341f821ea Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 10 May 2025 11:45:38 +0000 Subject: continue experimenting with user heap --- .../x86_64/include/arch/memory/heap/user_heap_allocator.hpp | 1 + arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'arch') 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 d698888..c50d2f6 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 @@ -18,6 +18,7 @@ namespace teachos::arch::memory::heap * @param heap_start Start of the allocatable heap area * @param heap_end End of the allocatable heap area (Start + Size) */ + [[gnu::section(".user_text")]] user_heap_allocator(std::size_t heap_start, std::size_t heap_end); /** 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 05fde8b..bc36361 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -143,10 +143,11 @@ namespace teachos::arch::memory::paging entry entry{section.flags}; // Required to be accesible in User Mode: - // - .user_text (Contains the actual code executed) - // - .boot_bss (Contains statically allocated variables) // - .boot_rodata (Contains constant data stored in ROM) + // - .boot_bss (Contains statically allocated variables) + // - .user_text (Contains the actual code executed) // - .user_data (Contains static user variables) + // - .stl_text (Contains code for custom std implementations) if (section.physical_address == 0x100000 /* .boot_rodata */ || section.physical_address == 0x102000 /* .boot_bss */ || section.physical_address == 0x218000 /* .stl_text */) @@ -155,8 +156,14 @@ namespace teachos::arch::memory::paging entry.set_global(); } + // TODO: We should be able to remove this somehow + if (section.physical_address == 0x209000 /* .text */) + { + entry.set_user_accesible(); + } + if (section.physical_address == 0x217000 /* .user_text */ || - section.physical_address == 0x21D000 /* .user_data */) + section.physical_address == 0x21E000 /* .user_data */) { entry.set_user_accesible(); } -- cgit v1.2.3 From 955ab48fe6329b2cbc8c5855a8ba7290185d0ea3 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 11 May 2025 07:20:54 +0000 Subject: rename page table entry function --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 8 ++++---- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') 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 bc36361..7321548 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -142,7 +142,7 @@ namespace teachos::arch::memory::paging allocator::frame_container const frames{begin, end}; entry entry{section.flags}; - // Required to be accesible in User Mode: + // Required to be accessible in User Mode: // - .boot_rodata (Contains constant data stored in ROM) // - .boot_bss (Contains statically allocated variables) // - .user_text (Contains the actual code executed) @@ -152,20 +152,20 @@ namespace teachos::arch::memory::paging section.physical_address == 0x102000 /* .boot_bss */ || section.physical_address == 0x218000 /* .stl_text */) { - entry.set_user_accesible(); + entry.set_user_accessible(); entry.set_global(); } // TODO: We should be able to remove this somehow if (section.physical_address == 0x209000 /* .text */) { - entry.set_user_accesible(); + entry.set_user_accessible(); } if (section.physical_address == 0x217000 /* .user_text */ || section.physical_address == 0x21E000 /* .user_data */) { - entry.set_user_accesible(); + entry.set_user_accessible(); } for (auto const & frame : frames) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 6ee1a13..03cdb1a 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -75,7 +75,7 @@ namespace teachos::arch::memory::paging * @brief Marks the page as accessible in User mode, meaning the underlying std::bitset has the 2nd bit aditonally * set. */ - auto set_user_accesible() -> void; + auto set_user_accessible() -> void; auto set_global() -> void; diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 57e33f7..a5b44fa 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -37,7 +37,7 @@ namespace teachos::arch::memory::paging auto entry::set_unused() -> void { flags = 0U; } - auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } auto entry::set_global() -> void { flags |= entry::GLOBAL; } -- cgit v1.2.3 From 833cd6446d9981a262959749c0e248e33b54c174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 11 May 2025 08:48:57 +0000 Subject: Adjust user heap allocator with expanding heap functionality --- .../arch/context_switching/syscall/main.hpp | 23 ++++++++++-- .../arch/memory/heap/user_heap_allocator.hpp | 9 +++++ arch/x86_64/src/context_switching/syscall/main.cpp | 17 ++++++--- .../context_switching/syscall/syscall_handler.cpp | 17 +++++++++ .../x86_64/src/memory/heap/user_heap_allocator.cpp | 41 +++++++++++++++++++++- 5 files changed, 99 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index 3af5a5a..8587ab2 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -15,6 +15,10 @@ namespace teachos::arch::context_switching::syscall { 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. }; /** @@ -23,7 +27,8 @@ namespace teachos::arch::context_switching::syscall */ enum class error { - OK = 0U, + OK = 0U, ///< No error occured in syscall. + OUT_OF_MEMORY = 1U, ///< Expanding heap failed because we have run out of mappable virtual address space. }; /** @@ -49,6 +54,16 @@ namespace teachos::arch::context_switching::syscall 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. @@ -58,10 +73,12 @@ namespace teachos::arch::context_switching::syscall * @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 Bool-convertable error code converting to true if the syscall failed or false if it didn't. + * @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 = {}) -> error; + auto syscall(type syscall_number, arguments args) -> response; } // namespace teachos::arch::context_switching::syscall 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 c50d2f6..cadec78 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 @@ -47,6 +47,15 @@ namespace teachos::arch::memory::heap */ [[gnu::section(".user_text")]] auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); } + /** + * @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. * diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index 93fc613..996d7fb 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -2,7 +2,7 @@ namespace teachos::arch::context_switching::syscall { - auto syscall(type syscall_number, arguments args) -> error + auto syscall(type syscall_number, arguments args) -> response { asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -18,9 +18,18 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - error error{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(error)); - return error; + error error_code{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); + + arguments values{}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); + + return {error_code, values}; } } // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index da9eb1b..b88f273 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -16,6 +16,20 @@ namespace teachos::arch::context_switching::syscall video::vga::text::newline(); return error::OK; } + + auto expand_user_heap() -> error + { + arguments args{}; + asm volatile("mov %[input], %%rdi" + : /* no output from call */ + : [input] "m"(args.arg_0) + : "memory"); + asm volatile("mov %[input], %%rsi" + : /* no output from call */ + : [input] "m"(args.arg_1) + : "memory"); + return error::OUT_OF_MEMORY; + } } // namespace auto syscall_handler() -> void @@ -46,6 +60,9 @@ namespace teachos::arch::context_switching::syscall case type::WRITE: result = write_to_vga_buffer(arg_0); break; + case type::EXPAND_HEAP: + result = expand_user_heap(); + break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); break; diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index 6843d66..ce8b0fa 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,5 +1,6 @@ #include "arch/memory/heap/user_heap_allocator.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" @@ -18,7 +19,7 @@ namespace teachos::arch::memory::heap heap_size > min_allocatable_size(), "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " "atleast one memory hole entry"); - first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + // first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); } auto user_heap_allocator::allocate(std::size_t size) -> void * @@ -57,6 +58,30 @@ namespace teachos::arch::memory::heap current = current->next; } + current = expand_heap_if_full(); + + if (current != nullptr) + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + } + exception_handling::panic("[Linked List Allocator] Out of memory"); } @@ -91,6 +116,20 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto user_heap_allocator::expand_heap_if_full() -> memory_block * + { + context_switching::syscall::arguments args{}; + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args); + + if (!result.error_code) + { + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + return nullptr; + } + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void * { -- cgit v1.2.3 From ef156dd6430855434b54275b22cd43ee3cedcfdc Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 11 May 2025 09:29:56 +0000 Subject: make frame_allocator and active_page_table statically available --- .../arch/memory/allocator/area_frame_allocator.hpp | 4 +- arch/x86_64/include/arch/memory/main.hpp | 14 +++++ .../include/arch/memory/paging/kernel_mapper.hpp | 3 +- .../context_switching/syscall/syscall_handler.cpp | 6 +++ arch/x86_64/src/memory/heap/memory_block.cpp | 1 + arch/x86_64/src/memory/main.cpp | 59 +++++++++++++--------- 6 files changed, 60 insertions(+), 27 deletions(-) (limited to 'arch') 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 2244613..6cb5f56 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 @@ -15,9 +15,9 @@ namespace teachos::arch::memory::allocator struct area_frame_allocator { /** - * @brief Constructor + * @brief Constructor. * - * @param mem_info Structure containg all relevant information to map and allocate memory + * @param mem_info Structure containg all relevant information to map and allocate memory. */ area_frame_allocator(multiboot::memory_information const & mem_info); diff --git a/arch/x86_64/include/arch/memory/main.hpp b/arch/x86_64/include/arch/memory/main.hpp index 164abbc..d51815f 100644 --- a/arch/x86_64/include/arch/memory/main.hpp +++ b/arch/x86_64/include/arch/memory/main.hpp @@ -1,8 +1,22 @@ #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. * 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 7321548..756eeb1 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -38,7 +38,7 @@ namespace teachos::arch::memory::paging * 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() -> active_page_table & + auto remap_kernel() -> void { // Set Page Global Enable bit auto cr4 = kernel::cpu::read_control_register(kernel::cpu::control_register::CR4); @@ -57,7 +57,6 @@ namespace teachos::arch::memory::paging 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); - return active_table; } private: diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index b88f273..9ca03d9 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -2,6 +2,8 @@ #include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/panic.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/memory/main.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching::syscall @@ -19,6 +21,10 @@ namespace teachos::arch::context_switching::syscall auto expand_user_heap() -> error { + // TODO: use actual addresses instead of this constant! + memory::remap_heap(memory::heap::USER_HEAP_SIZE + memory::heap::USER_HEAP_SIZE, memory::heap::USER_HEAP_SIZE, + memory::paging::entry::USER_ACCESSIBLE); + arguments args{}; asm volatile("mov %[input], %%rdi" : /* no output from call */ diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 446cd96..9f1fea8 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -6,6 +6,7 @@ namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) { + // TODO: Figure out why this memset fails memset(static_cast(this), 0, size); this->size = size; this->next = next; diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 4cdfa80..595cb0d 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -9,37 +9,47 @@ #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" +#include + namespace teachos::arch::memory { namespace { - template - auto create_frame_allocator(multiboot::memory_information const & memory_information) -> T + static std::optional frame_allocator; + + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::area_frame_allocator { - return allocator::area_frame_allocator{memory_information}; + frame_allocator.emplace(memory_information); + return frame_allocator.value(); } - template - auto remap_heap(T & allocator, paging::active_page_table & active_table, bool is_user_heap = false) -> void + auto get_frame_allocator() -> allocator::area_frame_allocator { - auto const heap_start = is_user_heap ? heap::USER_HEAP_START : heap::KERNEL_HEAP_START; - auto const heap_size = is_user_heap ? heap::USER_HEAP_SIZE : heap::KERNEL_HEAP_SIZE; + exception_handling::assert(frame_allocator.has_value(), "[Memory main] Frame allocator has not been created yet"); + return frame_allocator.value(); + } + } // namespace + + auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void + { + auto allocator = get_frame_allocator(); + decltype(auto) active_table = paging::active_page_table::create_or_get(); + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - auto const start_page = paging::virtual_page::containing_address(heap_start); - auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - paging::page_container::iterator const begin{start_page}; - paging::page_container::iterator const end{end_page}; - paging::page_container const pages{begin, end}; + paging::page_container::iterator const begin{start_page}; + paging::page_container::iterator const end{end_page}; + paging::page_container const pages{begin, end}; - constexpr auto base_flags = paging::entry::WRITABLE; - auto const flags = is_user_heap ? base_flags | paging::entry::USER_ACCESSIBLE : base_flags; + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = base_flags | additional_flags; - for (auto const & page : pages) - { - active_table.map_page_to_next_free_frame(allocator, page, flags); - } + for (auto const & page : pages) + { + active_table.map_page_to_next_free_frame(allocator, page, flags); } - } // namespace + } auto initialize_memory_management() -> void { @@ -49,18 +59,21 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); - auto & active_table = kernel.remap_kernel(); + kernel.remap_kernel(); video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - remap_heap(allocator, active_table); // Remap kernel heap - remap_heap(allocator, active_table, true); // Remap user heap + // Remap kernel heap + remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + // Remap user heap + remap_heap(heap::USER_HEAP_SIZE, heap::USER_HEAP_SIZE, paging::entry::USER_ACCESSIBLE); + video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From ee4c61f7313fedd23d01c69ea5036fa38ef6248a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 12 May 2025 08:50:12 +0000 Subject: Adjust user heap to lazy allocate heap --- .../include/arch/memory/heap/linked_list_allocator.hpp | 6 ++---- .../include/arch/memory/heap/user_heap_allocator.hpp | 12 +++--------- .../src/context_switching/syscall/syscall_handler.cpp | 10 +++++----- arch/x86_64/src/memory/heap/global_heap_allocator.cpp | 2 +- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 4 +--- arch/x86_64/src/memory/heap/memory_block.cpp | 4 ++-- arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 14 -------------- arch/x86_64/src/memory/main.cpp | 4 ---- 8 files changed, 14 insertions(+), 42 deletions(-) (limited to 'arch') 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 377533c..582b4af 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 @@ -111,10 +111,8 @@ namespace teachos::arch::memory::heap auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, std::size_t size) -> void; - std::size_t heap_start; ///< Start of the allocatable heap area. - std::size_t heap_end; ///< End of the allocatable heap area. - memory_block * first; ///< First free entry in our memory. - stl::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. + memory_block * first; ///< First free entry in our memory. + stl::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 cadec78..9c04718 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 @@ -14,12 +14,8 @@ namespace teachos::arch::memory::heap { /** * @brief Constructor. - * - * @param heap_start Start of the allocatable heap area - * @param heap_end End of the allocatable heap area (Start + Size) */ - [[gnu::section(".user_text")]] - user_heap_allocator(std::size_t heap_start, std::size_t heap_end); + user_heap_allocator() = default; /** * @copybrief heap_allocator::allocate @@ -126,10 +122,8 @@ namespace teachos::arch::memory::heap auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, std::size_t size) -> void; - std::size_t heap_start; ///< Start of the allocatable heap area. - std::size_t heap_end; ///< End of the allocatable heap area. - memory_block * first; ///< First free entry in our memory. - stl::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. + memory_block * first = {}; ///< First free entry in our memory. + stl::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/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 9ca03d9..7272e9e 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -21,11 +21,10 @@ namespace teachos::arch::context_switching::syscall auto expand_user_heap() -> error { - // TODO: use actual addresses instead of this constant! - memory::remap_heap(memory::heap::USER_HEAP_SIZE + memory::heap::USER_HEAP_SIZE, memory::heap::USER_HEAP_SIZE, - memory::paging::entry::USER_ACCESSIBLE); + static auto current_heap_end = memory::heap::USER_HEAP_START; + memory::remap_heap(current_heap_end, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); - arguments args{}; + arguments args{current_heap_end, memory::heap::USER_HEAP_SIZE}; asm volatile("mov %[input], %%rdi" : /* no output from call */ : [input] "m"(args.arg_0) @@ -34,7 +33,8 @@ namespace teachos::arch::context_switching::syscall : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); - return error::OUT_OF_MEMORY; + current_heap_end += memory::heap::USER_HEAP_SIZE; + return error::OK; } } // namespace diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index 23e2458..e6c268a 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -41,7 +41,7 @@ namespace teachos::arch::memory::heap } [[gnu::section(".user_data")]] - static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + static user_heap_allocator user_allocator{}; user_allocator_instance = &user_allocator; } diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index 5101ab2..63a6111 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -8,9 +8,7 @@ namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start(heap_start) - , heap_end(heap_end) - , first(nullptr) + : first(nullptr) , mutex{stl::mutex{}} { auto const heap_size = heap_end - heap_start; diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 9f1fea8..6ee675a 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -7,10 +7,10 @@ namespace teachos::arch::memory::heap memory_block::memory_block(std::size_t size, memory_block * next) { // TODO: Figure out why this memset fails - memset(static_cast(this), 0, size); + // memset(static_cast(this), 0, size); this->size = size; this->next = next; } - memory_block::~memory_block() { memset(static_cast(this), 0, sizeof(memory_block)); } + memory_block::~memory_block() { /*memset(static_cast(this), 0, sizeof(memory_block));*/ } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index ce8b0fa..9cb6c17 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -8,20 +8,6 @@ namespace teachos::arch::memory::heap { - user_heap_allocator::user_heap_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start(heap_start) - , heap_end(heap_end) - , first(nullptr) - , mutex{stl::mutex{}} - { - auto const heap_size = heap_end - heap_start; - exception_handling::assert( - heap_size > min_allocatable_size(), - "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " - "atleast one memory hole entry"); - // first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - auto user_heap_allocator::allocate(std::size_t size) -> void * { // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 595cb0d..5e671ac 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -69,11 +69,7 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - // Remap kernel heap remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - // Remap user heap - remap_heap(heap::USER_HEAP_SIZE, heap::USER_HEAP_SIZE, paging::entry::USER_ACCESSIBLE); - video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From 29e067867e7a437d12351b481024d4bab431b202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 12 May 2025 13:51:12 +0000 Subject: Fix crashes because of are frame allocator copy --- .../arch/context_switching/syscall/main.hpp | 6 +-- .../include/arch/memory/heap/memory_block.hpp | 2 + .../include/arch/memory/paging/kernel_mapper.hpp | 2 +- arch/x86_64/src/context_switching/syscall/main.cpp | 6 +-- .../context_switching/syscall/syscall_handler.cpp | 50 ++++++++++++++-------- arch/x86_64/src/memory/heap/memory_block.cpp | 5 +-- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 13 ++---- arch/x86_64/src/memory/main.cpp | 11 ++--- 8 files changed, 54 insertions(+), 41 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index 8587ab2..9d61f97 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -60,8 +60,8 @@ namespace teachos::arch::context_switching::syscall */ 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. + 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. }; /** @@ -78,7 +78,7 @@ namespace teachos::arch::context_switching::syscall * 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; + auto syscall(type syscall_number, arguments args = {}) -> response; } // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp index e1cd288..9d1fb02 100644 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -18,6 +18,7 @@ namespace teachos::arch::memory::heap * @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); /** @@ -26,6 +27,7 @@ namespace teachos::arch::memory::heap * @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 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 756eeb1..ca7e2f9 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -45,7 +45,7 @@ namespace teachos::arch::memory::paging kernel::cpu::write_control_register(kernel::cpu::control_register::CR4, cr4 | 0x80); temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; - auto & active_table = active_page_table::create_or_get(); + 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"); diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index 996d7fb..e291c10 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -18,9 +18,6 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - error error_code{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); - arguments values{}; asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); @@ -29,6 +26,9 @@ namespace teachos::arch::context_switching::syscall asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); + error error_code{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); + return {error_code, values}; } diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 7272e9e..9cc6edf 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -11,30 +11,21 @@ namespace teachos::arch::context_switching::syscall namespace { - auto write_to_vga_buffer(uint64_t buffer) -> error + auto write_to_vga_buffer(uint64_t buffer) -> response { video::vga::text::write(reinterpret_cast(buffer), video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - return error::OK; + return {error::OK}; } - auto expand_user_heap() -> error + auto expand_user_heap() -> response { static auto current_heap_end = memory::heap::USER_HEAP_START; - memory::remap_heap(current_heap_end, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); - - arguments args{current_heap_end, memory::heap::USER_HEAP_SIZE}; - asm volatile("mov %[input], %%rdi" - : /* no output from call */ - : [input] "m"(args.arg_0) - : "memory"); - asm volatile("mov %[input], %%rsi" - : /* no output from call */ - : [input] "m"(args.arg_1) - : "memory"); + uint64_t const heap_start = current_heap_end; + memory::remap_heap(heap_start, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); current_heap_end += memory::heap::USER_HEAP_SIZE; - return error::OK; + return {error::OK, {heap_start, memory::heap::USER_HEAP_SIZE}}; } } // namespace @@ -60,7 +51,7 @@ namespace teachos::arch::context_switching::syscall // and now. asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); - error result = error::OK; + response result; switch (static_cast(syscall_number)) { case type::WRITE: @@ -76,7 +67,32 @@ namespace teachos::arch::context_switching::syscall asm volatile("mov %[input], %%rax" : /* no output from call */ - : [input] "m"(result) + : [input] "m"(result.error_code) + : "memory"); + + asm volatile("mov %[input], %%rdi" + : /* no output from call */ + : [input] "m"(result.values.arg_0) + : "memory"); + asm volatile("mov %[input], %%rsi" + : /* no output from call */ + : [input] "m"(result.values.arg_1) + : "memory"); + asm volatile("mov %[input], %%rdx" + : /* no output from call */ + : [input] "m"(result.values.arg_2) + : "memory"); + asm volatile("mov %[input], %%r10" + : /* no output from call */ + : [input] "m"(result.values.arg_3) + : "memory"); + asm volatile("mov %[input], %%r8" + : /* no output from call */ + : [input] "m"(result.values.arg_4) + : "memory"); + asm volatile("mov %[input], %%r9" + : /* no output from call */ + : [input] "m"(result.values.arg_5) : "memory"); asm volatile("mov %[input], %%rcx" diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 6ee675a..bc97bd6 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -6,11 +6,10 @@ namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) { - // TODO: Figure out why this memset fails - // memset(static_cast(this), 0, size); + memset(static_cast(this), 0U, size); this->size = size; this->next = next; } - memory_block::~memory_block() { /*memset(static_cast(this), 0, sizeof(memory_block));*/ } + memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index 9cb6c17..f3fe1c2 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -104,16 +104,11 @@ namespace teachos::arch::memory::heap auto user_heap_allocator::expand_heap_if_full() -> memory_block * { - context_switching::syscall::arguments args{}; - auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args); + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); - if (!result.error_code) - { - uint64_t const heap_start = result.values.arg_0; - uint64_t const heap_size = result.values.arg_1; - return new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - return nullptr; + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; } auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 5e671ac..2746a71 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -18,22 +18,23 @@ namespace teachos::arch::memory static std::optional frame_allocator; auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::area_frame_allocator + -> allocator::area_frame_allocator & { frame_allocator.emplace(memory_information); return frame_allocator.value(); } - auto get_frame_allocator() -> allocator::area_frame_allocator + auto get_frame_allocator() -> allocator::area_frame_allocator & { - exception_handling::assert(frame_allocator.has_value(), "[Memory main] Frame allocator has not been created yet"); + exception_handling::assert(frame_allocator.has_value(), + "[Initialization] Frame allocator has not been created yet"); return frame_allocator.value(); } } // namespace auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void { - auto allocator = get_frame_allocator(); + decltype(auto) allocator = get_frame_allocator(); decltype(auto) active_table = paging::active_page_table::create_or_get(); auto const start_page = paging::virtual_page::containing_address(heap_start); auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); @@ -59,7 +60,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + decltype(auto) allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 06b6e20ba921a062b71c86df8859eaaea4b75cb2 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 15 May 2025 12:20:19 +0000 Subject: add cpp standard library to .stl_text section (which is user accessible) --- arch/x86_64/scripts/kernel.ld | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 1856123..1925872 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -88,6 +88,7 @@ SECTIONS .text ALIGN(4K) : AT(ADDR (.text)) { *(.text*) + *(EXCLUDE_FILE (*libstdc++.a) .text .text.*) } .user_text ALIGN(4K) : AT(ADDR (.user_text)) @@ -98,6 +99,7 @@ SECTIONS .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) { *(.stl_text) + *libstdc++.a:*(.text .text.*) } .rodata ALIGN(4K) : AT (ADDR (.rodata)) -- cgit v1.2.3 From d4cc546df6eba2dd287785f1a63fbcce4a1b9bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 16 May 2025 09:58:57 +0000 Subject: Attempt to move atomic into stl text as well --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 12 ++++++------ arch/x86_64/scripts/kernel.ld | 16 ++++++++-------- arch/x86_64/src/user/main.cpp | 9 +++++++++ 3 files changed, 23 insertions(+), 14 deletions(-) (limited to 'arch') 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 ca7e2f9..94c937d 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -144,24 +144,24 @@ namespace teachos::arch::memory::paging // Required to be accessible in User Mode: // - .boot_rodata (Contains constant data stored in ROM) // - .boot_bss (Contains statically allocated variables) - // - .user_text (Contains the actual code executed) + // - .user_text (Contains the actual user code executed) // - .user_data (Contains static user variables) - // - .stl_text (Contains code for custom std implementations) + // - .stl_text (Contains code for custom std implementations and standard library code) if (section.physical_address == 0x100000 /* .boot_rodata */ || section.physical_address == 0x102000 /* .boot_bss */ || - section.physical_address == 0x218000 /* .stl_text */) + section.physical_address == 0x209000 /* .stl_text */) { entry.set_user_accessible(); entry.set_global(); } - // TODO: We should be able to remove this somehow - if (section.physical_address == 0x209000 /* .text */) + // TODO: Can be removed once stl has been completly mapped into stl text + if (section.physical_address == 0x20A000 /* .text */) { entry.set_user_accessible(); } - if (section.physical_address == 0x217000 /* .user_text */ || + if (section.physical_address == 0x218000 /* .user_text */ || section.physical_address == 0x21E000 /* .user_data */) { entry.set_user_accessible(); diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 1925872..e5cbc73 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -85,21 +85,21 @@ SECTIONS KEEP(*crtn.s.o*(.fini)) } - .text ALIGN(4K) : AT(ADDR (.text)) + .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) { - *(.text*) - *(EXCLUDE_FILE (*libstdc++.a) .text .text.*) + *(.stl_text) + KEEP(*libstdc++.a:*(.text .text.*)) + KEEP(*libatomic.a:*(.text .text.*)) /* Attempt to move atomic stl into stl_text as well, doesn't work */ } - .user_text ALIGN(4K) : AT(ADDR (.user_text)) + .text ALIGN(4K) : AT(ADDR (.text)) { - *(.user_text) + *(.text .text.*) } - .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) + .user_text ALIGN(4K) : AT(ADDR (.user_text)) { - *(.stl_text) - *libstdc++.a:*(.text .text.*) + *(.user_text) } .rodata ALIGN(4K) : AT (ADDR (.rodata)) diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 59647f8..a435a41 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -3,6 +3,9 @@ #include "arch/context_switching/syscall/main.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" +#include +#include + // TODO: Disallow these imports #include "arch/kernel/cpu/if.hpp" #include "arch/video/vga/text.hpp" @@ -17,6 +20,12 @@ namespace teachos::arch::user // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde + int test = std::max(5, 10); + (void)test; + + std::atomic locked = {false}; + locked.exchange(true); + auto address = memory::heap::global_heap_allocator::malloc(8U); (void)address; -- cgit v1.2.3 From 5c314eef566df2732973e8cb35974ec49748adba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 16 May 2025 13:27:16 +0000 Subject: Fix bug where level 4 to level 2 entries are not mapped user accesible. --- .../include/arch/memory/heap/user_heap_allocator.hpp | 3 +++ .../include/arch/memory/paging/active_page_table.hpp | 5 +---- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 5 +---- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 2 -- arch/x86_64/include/arch/memory/paging/page_table.hpp | 11 +++++++++-- arch/x86_64/scripts/kernel.ld | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 2 -- arch/x86_64/src/user/main.cpp | 16 ---------------- 8 files changed, 15 insertions(+), 31 deletions(-) (limited to 'arch') 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 9c04718..42af23f 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 @@ -32,6 +32,9 @@ namespace teachos::arch::memory::heap [[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; 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 index d77b76c..f68d8b6 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -82,10 +82,7 @@ namespace teachos::arch::memory::paging for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { - // Ignore all bits passed besides the entry::USER_ACCESSIBLE bit, because for the entry into the Level 4 up to - // Level 2 page, we always have to set the entry::PRESENT and entry::WRITABLE bit anyway. - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level), - flags.to_ulong() & entry::USER_ACCESSIBLE); + 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)]; 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 94c937d..5bf14fb 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -142,17 +142,14 @@ namespace teachos::arch::memory::paging entry entry{section.flags}; // Required to be accessible in User Mode: - // - .boot_rodata (Contains constant data stored in ROM) // - .boot_bss (Contains statically allocated variables) // - .user_text (Contains the actual user code executed) // - .user_data (Contains static user variables) // - .stl_text (Contains code for custom std implementations and standard library code) - if (section.physical_address == 0x100000 /* .boot_rodata */ || - section.physical_address == 0x102000 /* .boot_bss */ || + if (section.physical_address == 0x102000 /* .boot_bss */ || section.physical_address == 0x209000 /* .stl_text */) { entry.set_user_accessible(); - entry.set_global(); } // TODO: Can be removed once stl has been completly mapped into stl text diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 03cdb1a..8147c5c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -77,8 +77,6 @@ namespace teachos::arch::memory::paging */ auto set_user_accessible() -> void; - auto set_global() -> void; - /** * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in * memory. diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 7b7e29e..b972337 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -95,13 +95,20 @@ namespace teachos::arch::memory::paging { 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(), flags.to_ulong() | entry::PRESENT | entry::WRITABLE); + 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(); } diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index e5cbc73..23f9681 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -89,7 +89,7 @@ SECTIONS { *(.stl_text) KEEP(*libstdc++.a:*(.text .text.*)) - KEEP(*libatomic.a:*(.text .text.*)) /* Attempt to move atomic stl into stl_text as well, doesn't work */ + KEEP(*libatomic.a:*(.text .text.*)) /* TODO: Attempt to move atomic stl into stl_text as well, doesn't work */ } .text ALIGN(4K) : AT(ADDR (.text)) diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index a5b44fa..57045ca 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -39,8 +39,6 @@ namespace teachos::arch::memory::paging auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } - auto entry::set_global() -> void { flags |= entry::GLOBAL; } - auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index a435a41..747a8a4 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -6,10 +6,6 @@ #include #include -// TODO: Disallow these imports -#include "arch/kernel/cpu/if.hpp" -#include "arch/video/vga/text.hpp" - namespace teachos::arch::user { auto main() -> void @@ -18,8 +14,6 @@ namespace teachos::arch::user context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); - // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde - int test = std::max(5, 10); (void)test; @@ -29,16 +23,6 @@ namespace teachos::arch::user auto address = memory::heap::global_heap_allocator::malloc(8U); (void)address; - // auto test = new int{20}; // Causes crash Heap is not mapped in User Mode - // (void)test; - - // if (!error) - // { - // // Causes crash vga is not mapped in User Mode - // video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - // video::vga::text::common_attributes::green_on_black); - // } - for (;;) { } -- cgit v1.2.3 From 1b5a771a34743a2973a82de5ebdfd22da030b841 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 18 May 2025 13:21:42 +0000 Subject: update linker file and improve section parsing --- .../include/arch/memory/paging/kernel_mapper.hpp | 28 ++++++++++------------ arch/x86_64/scripts/kernel.ld | 7 +++--- arch/x86_64/src/user/main.cpp | 17 +++++++++---- 3 files changed, 27 insertions(+), 25 deletions(-) (limited to 'arch') 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 5bf14fb..977b40d 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -7,6 +7,9 @@ #include "arch/memory/paging/temporary_page.hpp" #include "arch/video/vga/text.hpp" +#include +#include + namespace teachos::arch::memory::paging { /** @@ -142,24 +145,17 @@ namespace teachos::arch::memory::paging entry entry{section.flags}; // Required to be accessible in User Mode: - // - .boot_bss (Contains statically allocated variables) - // - .user_text (Contains the actual user code executed) - // - .user_data (Contains static user variables) - // - .stl_text (Contains code for custom std implementations and standard library code) - if (section.physical_address == 0x102000 /* .boot_bss */ || - section.physical_address == 0x209000 /* .stl_text */) - { - entry.set_user_accessible(); - } + constexpr std::array user_section_bases = { + 0x102000, // .boot_bss (Contains statically allocated variables) + 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) + 0x218000, // .user_text (Contains the actual user code executed) + 0x21E000, // .user_data (Contains static user variables) - // TODO: Can be removed once stl has been completly mapped into stl text - if (section.physical_address == 0x20A000 /* .text */) - { - entry.set_user_accessible(); - } + 0x20A000 // .text (Necessary, because symbols for standard library are placed there) + }; - if (section.physical_address == 0x218000 /* .user_text */ || - section.physical_address == 0x21E000 /* .user_data */) + if (std::find(user_section_bases.begin(), user_section_bases.end(), section.physical_address) != + user_section_bases.end()) { entry.set_user_accessible(); } diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 23f9681..3d9a7ae 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -87,9 +87,8 @@ SECTIONS .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) { - *(.stl_text) + *(.stl_text .stl_text*) KEEP(*libstdc++.a:*(.text .text.*)) - KEEP(*libatomic.a:*(.text .text.*)) /* TODO: Attempt to move atomic stl into stl_text as well, doesn't work */ } .text ALIGN(4K) : AT(ADDR (.text)) @@ -99,7 +98,7 @@ SECTIONS .user_text ALIGN(4K) : AT(ADDR (.user_text)) { - *(.user_text) + *(.user_text .user_text.*) } .rodata ALIGN(4K) : AT (ADDR (.rodata)) @@ -137,7 +136,7 @@ SECTIONS .user_data ALIGN(4K) : AT (ADDR (.user_data)) { - *(.user_data*) + *(.user_data .user_data.*) } /*************************************************************************** diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 747a8a4..e621327 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -4,22 +4,29 @@ #include "arch/memory/heap/global_heap_allocator.hpp" #include +#include #include +#include namespace teachos::arch::user { auto main() -> void { + // Test writing to VGA Buffer char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); - int test = std::max(5, 10); - (void)test; - - std::atomic locked = {false}; - locked.exchange(true); + // Test C++ standard library + std::array, 4> array_test = {std::atomic{5}, std::atomic{10}, + std::atomic{15}, std::atomic{20}}; + std::ranges::for_each(array_test, [](auto & item) { + auto value = item.load(); + uint8_t max_value = std::max(value, uint8_t{10}); + item.exchange(max_value + 2); + }); + // Test user heap auto address = memory::heap::global_heap_allocator::malloc(8U); (void)address; -- cgit v1.2.3 From 8d39f3f67734bf39cada370c39243e6ef33bf4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 18 May 2025 14:45:05 +0000 Subject: Make new usable for both kernel and user calls --- .../segment_selector.hpp | 8 +++ .../arch/context_switching/syscall/main.hpp | 3 + .../include/arch/kernel/cpu/segment_register.hpp | 1 + .../arch/memory/heap/global_heap_allocator.hpp | 6 ++ .../segment_selector.cpp | 2 + .../context_switching/syscall/syscall_handler.cpp | 6 ++ .../src/memory/heap/global_heap_allocator.cpp | 66 +++++++++++++++++----- arch/x86_64/src/user/main.cpp | 6 +- 8 files changed, 79 insertions(+), 19 deletions(-) (limited to 'arch') 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 index 5be449f..82719bc 100644 --- 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 @@ -66,6 +66,14 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table */ auto contains_flags(std::bitset<3U> other) const -> bool; + /** + * @brief Gets the index into the global 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. */ diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index 9d61f97..e391c1f 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -19,6 +19,9 @@ namespace teachos::arch::context_switching::syscall /// 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. }; /** diff --git a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp index 36ada23..a236452 100644 --- a/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/segment_register.hpp @@ -31,6 +31,7 @@ namespace teachos::arch::kernel::cpu * * @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; /** 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 index 6fcab6f..c98c130 100644 --- a/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/global_heap_allocator.hpp @@ -97,16 +97,22 @@ namespace teachos::arch::memory::heap }; } // 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/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp index 8568447..27f0a3b 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -7,6 +7,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table return (std::bitset<3U>{_flags} & other) == other; } + auto segment_selector::get_index() const -> uint16_t { return _index; } + auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } segment_selector::operator uint16_t() const { return *reinterpret_cast(this); } diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 9cc6edf..cd1c8a2 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -60,6 +60,12 @@ namespace teachos::arch::context_switching::syscall case type::EXPAND_HEAP: result = expand_user_heap(); break; + case type::ASSERT: + if (!arg_0) + { + teachos::arch::exception_handling::panic(reinterpret_cast(arg_1)); + } + break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); break; diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index e6c268a..35cd623 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -1,12 +1,29 @@ #include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/linked_list_allocator.hpp" #include "arch/memory/heap/user_heap_allocator.hpp" namespace teachos::arch::memory::heap { + namespace + { + constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."; + constexpr uint16_t KERNEL_CODE_INDEX = 1U; + + [[gnu::section(".user_text")]] + auto os_in_kernel_mode() -> bool + { + auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); + return cs.get_index() == KERNEL_CODE_INDEX; + } + } // namespace + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; @@ -47,53 +64,72 @@ namespace teachos::arch::memory::heap auto global_heap_allocator::kernel() -> heap_allocator & { - exception_handling::assert(kernel_allocator_instance != nullptr, - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."); + exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); return *kernel_allocator_instance; } auto global_heap_allocator::user() -> user_heap_allocator & { - // TODO: Assert Method does not exist in .user_text meaning this causes a Page Fault when accessed, Make it into a - // syscall instead - // exception_handling::assert(user_allocator_instance != nullptr, - // "Attempted to allocate or deallocate using the global_heap_allocator before " - // "register_heap_allocation_type was called."); - + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); return *user_allocator_instance; } } // namespace teachos::arch::memory::heap auto operator new(std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); } auto operator delete(void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator delete(void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator new[](std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); } auto operator delete[](void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator delete[](void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index e621327..8b07e4a 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -12,8 +12,7 @@ namespace teachos::arch::user { auto main() -> void { - // Test writing to VGA Buffer - char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + constexpr char syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); @@ -26,8 +25,7 @@ namespace teachos::arch::user item.exchange(max_value + 2); }); - // Test user heap - auto address = memory::heap::global_heap_allocator::malloc(8U); + auto address = new uint64_t{10U}; (void)address; for (;;) -- cgit v1.2.3 From 8a6a9a3a159ce1b960721eb921b8e8d81b15b718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 20 May 2025 12:29:09 +0000 Subject: Improve syscalls and user heap allocator --- .../arch/memory/heap/user_heap_allocator.hpp | 15 ++++ .../include/arch/memory/paging/kernel_mapper.hpp | 20 +++--- arch/x86_64/scripts/kernel.ld | 6 ++ .../context_switching/syscall/syscall_handler.cpp | 6 +- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 80 +++++++++++----------- 5 files changed, 71 insertions(+), 56 deletions(-) (limited to 'arch') 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 42af23f..6b1b7bb 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 @@ -4,6 +4,8 @@ #include "arch/memory/heap/memory_block.hpp" #include "arch/stl/mutex.hpp" +#include + namespace teachos::arch::memory::heap { /** @@ -46,6 +48,19 @@ namespace teachos::arch::memory::heap */ [[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 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 977b40d..b211b8b 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -124,6 +124,13 @@ namespace teachos::arch::memory::paging auto map_elf_kernel_sections(active_page_table & active_table) -> void { exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); + std::array constexpr USER_SECTION_BASES = { + 0x102000, // .boot_bss (Contains statically allocated variables) + 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) + 0x218000, // .user_text (Contains the actual user code executed) + 0x21F000, // .user_data (Contains static user variables) + }; + for (auto const & section : mem_info.sections) { if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) @@ -144,18 +151,7 @@ namespace teachos::arch::memory::paging allocator::frame_container const frames{begin, end}; entry entry{section.flags}; - // Required to be accessible in User Mode: - constexpr std::array user_section_bases = { - 0x102000, // .boot_bss (Contains statically allocated variables) - 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) - 0x218000, // .user_text (Contains the actual user code executed) - 0x21E000, // .user_data (Contains static user variables) - - 0x20A000 // .text (Necessary, because symbols for standard library are placed there) - }; - - if (std::find(user_section_bases.begin(), user_section_bases.end(), section.physical_address) != - user_section_bases.end()) + if (std::ranges::find(USER_SECTION_BASES, section.physical_address) != USER_SECTION_BASES.end()) { entry.set_user_accessible(); } diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 3d9a7ae..df9d7e7 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -89,6 +89,12 @@ SECTIONS { *(.stl_text .stl_text*) KEEP(*libstdc++.a:*(.text .text.*)) + KEEP(*libubsan.a:*(.text .text.*)) /* TODO: Include atomic_base into stl_text / Print where code lies: objdump -t build/bin/Debug/_kernel >> test.txt */ + KEEP(*liblsan.a:*(.text .text.*)) + KEEP(*libtsan.a:*(.text .text.*)) + KEEP(*libasan.a:*(.text .text.*)) + KEEP(*libgcc.a:*(.text .text.*)) + KEEP(*libatomic.a:*(.text .text.*)) } .text ALIGN(4K) : AT(ADDR (.text)) diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index cd1c8a2..af6d911 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -1,6 +1,7 @@ #include "arch/context_switching/syscall/syscall_handler.hpp" #include "arch/context_switching/syscall/main.hpp" +#include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -61,10 +62,7 @@ namespace teachos::arch::context_switching::syscall result = expand_user_heap(); break; case type::ASSERT: - if (!arg_0) - { - teachos::arch::exception_handling::panic(reinterpret_cast(arg_1)); - } + teachos::arch::exception_handling::assert(arg_0, reinterpret_cast(arg_1)); break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index f3fe1c2..427a68a 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,8 +1,6 @@ #include "arch/memory/heap/user_heap_allocator.hpp" #include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" #include @@ -20,24 +18,10 @@ namespace teachos::arch::memory::heap while (current != nullptr) { - // TODO: Can not access current pointer. Results in a General Protection Fault? - if (current->size == total_size) + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + return memory.value(); } previous = current; @@ -48,27 +32,17 @@ namespace teachos::arch::memory::heap if (current != nullptr) { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + return memory.value(); } } - exception_handling::panic("[Linked List Allocator] Out of memory"); + char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; + context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, + {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); + return nullptr; } auto user_heap_allocator::deallocate(void * pointer) noexcept -> void @@ -102,6 +76,30 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, + std::size_t total_size) -> std::optional + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + return std::nullopt; + } + auto user_heap_allocator::expand_heap_if_full() -> memory_block * { auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); @@ -180,10 +178,12 @@ namespace teachos::arch::memory::heap // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean // that the block has already been deallocated and we therefore attempted a double free. - exception_handling::assert(previous_block == nullptr || - start_address >= - (reinterpret_cast(previous_block) + previous_block->size), - "[Linked List Allocator] Attempted double free detected"); + char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {previous_block == nullptr || + start_address >= (reinterpret_cast(previous_block) + previous_block->size), + reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); auto const new_block = new (pointer) memory_block(block_size, next_block); // If we want to deallocate the first block that is before any other free block, then there exists no previous free -- cgit v1.2.3 From 3e597ede8079883b3b9d48faf94b8a7bec2a2118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 27 May 2025 12:41:50 +0000 Subject: Readd text kernels ection with explanation --- arch/x86_64/include/arch/context_switching/syscall/main.hpp | 2 +- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 3 +++ arch/x86_64/src/context_switching/syscall/syscall_handler.cpp | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp index e391c1f..59adc13 100644 --- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp +++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp @@ -28,7 +28,7 @@ namespace teachos::arch::context_switching::syscall * @brief Possible error codes that can be returned by the different syscall methods called depending on the type * enum. */ - enum class error + 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. 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 b211b8b..81ac0cb 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -129,6 +129,9 @@ namespace teachos::arch::memory::paging 0x209000, // .stl_text (Contains code for custom std implementations and standard library code) 0x218000, // .user_text (Contains the actual user code executed) 0x21F000, // .user_data (Contains static user variables) + + 0x20A000 // .text (Necessary, because symbols for all template standard library features are placed here if + // they were first used in the Kernel Code Section) }; for (auto const & section : mem_info.sections) diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index af6d911..84dbe5f 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -108,9 +108,9 @@ namespace teachos::arch::context_switching::syscall : [input] "m"(rflags) : "memory"); - // Additionally call leave, because x86 allocates tack space for the internal variables. If we do not clean up this + // Additionally call leave, because x86 allocates stack space for the internal variables. If we do not clean up this // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the - // method that originally called it, becuase the RIP has not been restored from the previous stack frame. + // method that originally called it, because the RIP has not been restored from the previous stack frame. asm volatile("leave\n" "sysretq"); } -- cgit v1.2.3 From 9f2e780030e2101d5f7f01f42df805db9a5fa809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 30 May 2025 12:48:57 +0000 Subject: Clean up files --- arch/x86_64/CMakeLists.txt | 1 - .../memory/allocator/stack_frame_allocator.hpp | 67 ------------- arch/x86_64/scripts/kernel.ld | 6 -- .../src/memory/allocator/stack_frame_allocator.cpp | 105 --------------------- 4 files changed, 179 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp delete mode 100644 arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 0a6ab9c..57b3a60 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -54,7 +54,6 @@ target_sources("_memory" PRIVATE "src/memory/multiboot/elf_symbols_section.cpp" "src/memory/multiboot/reader.cpp" "src/memory/allocator/area_frame_allocator.cpp" - "src/memory/allocator/stack_frame_allocator.cpp" "src/memory/allocator/tiny_frame_allocator.cpp" "src/memory/allocator/physical_frame.cpp" "src/memory/paging/page_entry.cpp" diff --git a/arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp deleted file mode 100644 index a8e7233..0000000 --- a/arch/x86_64/include/arch/memory/allocator/stack_frame_allocator.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_STACK_FRAME_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_STACK_FRAME_ALLOCATOR_HPP - -#include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/multiboot/reader.hpp" -#include "arch/stl/stack.hpp" - -#include - -namespace teachos::arch::memory::allocator -{ - /** - * @brief Uses an internal stack-like dynamic structure to keep track of the address of all avaialable physical frames - * that are available using the memory areas read from the multiboot2 information pointer and simply pushes - * deallocated frames back onto the stack. Allows for constant speed O(1) allocation and deallocation - */ - struct stack_frame_allocator - { - /** - * @brief Constructor - * - * @param mem_info Structure containg all relevant information to map and allocate memory - */ - stack_frame_allocator(multiboot::memory_information const & mem_info); - - /** - * @brief Allocate memory by finding and returning 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. - * - * @param physical_frame Previously allocated physical_frame that should be deallocated. - */ - auto deallocate_frame(physical_frame const & physical_frame) -> void; - - private: - /** - * @brief Load all initally free physical frames from the current memory area into the underlying stack data - * structure so they can simply be accessed once required. Recallling the method will load all free physical frames - * from the next free memory area until there are no memory areas left. - */ - auto load_free_physical_frames() -> void; - - /** - * @brief Find the next memory area and write it into current_area. - */ - auto choose_next_area() -> void; - - stl::stack free_frames; ///< All currently free physical frames in a LIFO (last-in, first-out) - ///< data structure. - 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 teachos::arch::memory::allocator - -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_STACK_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index df9d7e7..3d9a7ae 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -89,12 +89,6 @@ SECTIONS { *(.stl_text .stl_text*) KEEP(*libstdc++.a:*(.text .text.*)) - KEEP(*libubsan.a:*(.text .text.*)) /* TODO: Include atomic_base into stl_text / Print where code lies: objdump -t build/bin/Debug/_kernel >> test.txt */ - KEEP(*liblsan.a:*(.text .text.*)) - KEEP(*libtsan.a:*(.text .text.*)) - KEEP(*libasan.a:*(.text .text.*)) - KEEP(*libgcc.a:*(.text .text.*)) - KEEP(*libatomic.a:*(.text .text.*)) } .text ALIGN(4K) : AT(ADDR (.text)) diff --git a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp deleted file mode 100644 index 0fa277a..0000000 --- a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "arch/memory/allocator/stack_frame_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::allocator -{ - stack_frame_allocator::stack_frame_allocator(multiboot::memory_information const & mem_info) - : free_frames() - , next_free_frame() - , current_area(std::nullopt) - , memory_areas(mem_info.areas) - , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) - , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) - , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) - , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) - { - load_free_physical_frames(); - } - - auto stack_frame_allocator::load_free_physical_frames() -> void - { - choose_next_area(); - if (!current_area.has_value()) - { - return; - } - - auto const address = current_area.value().base_address + current_area.value().area_length - 1; - physical_frame const current_area_last_frame = physical_frame::containing_address(address); - - // Only try to allocate memory if current_area is not null, because - // the current_area is null if there is no more available memory. - while (next_free_frame <= current_area_last_frame) - { - if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; - } - else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; - } - else - { - // Frame is unused, increment `next_free_frame` and return it. - next_free_frame.frame_number += 1; - // TODO: Fix using heap like structure to initalize paging allocator used by heap does not work - // free_frames.push(next_free_frame); - static uint32_t count = 0U; - count++; - } - } - } - - auto stack_frame_allocator::choose_next_area() -> void - { - current_area = std::nullopt; - auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { - auto address = area.base_address + area.area_length - 1; - return physical_frame::containing_address(address) >= next_free_frame; - }); - - auto const lowest_area_with_free_frames = std::ranges::min_element( - next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); - - if (lowest_area_with_free_frames != next_area_with_free_frames.end()) - { - current_area = *lowest_area_with_free_frames; - // Update the `next_free_frame` according to the new memory area - auto const start_frame = physical_frame::containing_address(current_area.value().base_address); - if (next_free_frame < start_frame) - { - next_free_frame = start_frame; - } - } - } - - auto stack_frame_allocator::allocate_frame() -> std::optional - { - // If the underlying stack is empty that are no free frames left to allocate. - if (free_frames.empty()) - { - load_free_physical_frames(); - if (free_frames.empty()) - { - return std::nullopt; - } - } - - decltype(auto) top = free_frames.top(); - free_frames.pop(); - return top; - } - - auto stack_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void - { - free_frames.push(physical_frame); - } -} // namespace teachos::arch::memory::allocator -- cgit v1.2.3 From 1031a69ca5e23f2087148ad57e57506735872617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 4 Jun 2025 14:48:50 +0000 Subject: Adjust minor comments --- .../interrupt_descriptor_table/gate_descriptor.hpp | 2 +- .../context_switching/interrupt_descriptor_table/idt_flags.hpp | 6 +++--- .../interrupt_descriptor_table/ist_offset.hpp | 10 ++++++---- .../interrupt_descriptor_table/segment_selector.hpp | 5 +++-- .../context_switching/segment_descriptor_table/access_byte.hpp | 2 +- .../context_switching/segment_descriptor_table/gdt_flags.hpp | 2 +- .../arch/interrupt_handling/generic_interrupt_handler.hpp | 2 +- 7 files changed, 16 insertions(+), 13 deletions(-) (limited to 'arch') 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 index 22cd0f0..07110c8 100644 --- 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 @@ -30,7 +30,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table * 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 IST + * - 3 bit Interrupt Stack Table Offset * - 8 bit Type and Flags * - 64 bit Offset * 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 index 948f478..5104c36 100644 --- 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 @@ -14,7 +14,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table struct [[gnu::packed]] idt_flags { /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + * @brief Possible set bits in our underlying bits and the meaning when they are set. */ enum bitset : uint8_t { @@ -59,10 +59,10 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto contains_flags(std::bitset<8U> other) const -> bool; /** - * @brief Allows to compare the underlying std::bitset of two instances. + * @brief Allows to compare the underlying bits 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. + * @return Whether the underlying set bits of both types are the same. */ auto operator==(idt_flags const & other) const -> bool = default; 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 index cefe1b2..e45bcf4 100644 --- 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 @@ -7,7 +7,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { /** - * @brief Defines helper function for all states that the ist field of a gate descriptor can + * @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. */ @@ -21,9 +21,11 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table /** * @brief Constructor. * - * @param index Index into local or global descriptor table. + * @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 index); + ist_offset(uint8_t offset); /** * @brief Allows to compare the underlying set bits of two instances. @@ -34,7 +36,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table 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 menas we do not switch stacks, + 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. }; 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 index 82719bc..2a7704e 100644 --- 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 @@ -17,7 +17,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table struct [[gnu::packed]] segment_selector { /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + * @brief Possible set bits in our underlying bits and the meaning when they are set. */ enum bitset : uint8_t { @@ -67,7 +67,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto contains_flags(std::bitset<3U> other) const -> bool; /** - * @brief Gets the index into the global descriptor table this segment selector is pointing too. + * @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. */ 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 index 621b570..7450330 100644 --- 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 @@ -14,7 +14,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table struct [[gnu::packed]] access_byte { /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + * @brief Possible set bits in our underlying bits and the meaning when they are set. */ enum bitset : uint8_t { 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 index 4b84035..e24b988 100644 --- 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 @@ -14,7 +14,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table struct [[gnu::packed]] gdt_flags { /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + * @brief Possible set bits in our underlying bits and the meaning when they are set. */ enum bitset : uint8_t { 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 index 2d26668..15b35c1 100644 --- a/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ b/arch/x86_64/include/arch/interrupt_handling/generic_interrupt_handler.hpp @@ -13,7 +13,7 @@ namespace teachos::arch::interrupt_handling */ struct [[gnu::packed]] interrupt_frame { - // uint64_t error_code; ///< Error code pushed by some exceptions. + // 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. -- cgit v1.2.3