diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-07-24 16:35:34 +0000 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-07-24 16:35:34 +0000 |
| commit | 2d3399ab6072acd85811a54fce8eff50628888b6 (patch) | |
| tree | bb6f63b58861938c6e15492732b440459dd22d62 /arch/x86_64/pre/include | |
| parent | 1b65136a11453fe7e89320dfe6170a0cd75e60dd (diff) | |
| download | teachos-2d3399ab6072acd85811a54fce8eff50628888b6.tar.xz teachos-2d3399ab6072acd85811a54fce8eff50628888b6.zip | |
x86_64: move files out of the way
Diffstat (limited to 'arch/x86_64/pre/include')
50 files changed, 3223 insertions, 0 deletions
diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp new file mode 100644 index 0000000..07110c8 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp @@ -0,0 +1,69 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP + +#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" +#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +#include <bitset> +#include <cstdint> + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + __extension__ typedef __int128 int128_t; + __extension__ typedef unsigned __int128 uint128_t; + + /** + * @brief Defines helper function for all states and the actual data the gate descriptor can have. + */ + struct [[gnu::packed]] gate_descriptor + { + /** + * @brief Default Constructor. + */ + gate_descriptor() = default; + + /** + * @brief Constructor. + * + * @note Created gate descriptor copies the given bytes into these components ending with a 32 bit reserved + * field that has to be used, because the 64-bit gate descriptor needs to be big enough for two 32-bit gate + * descriptor. + * - 16 bit Segment Selector + * - 3 bit Interrupt Stack Table Offset + * - 8 bit Type and Flags + * - 64 bit Offset + * + * @param flags Copies the bits set from the given data into the individual components of a gate + * descriptor. + */ + explicit gate_descriptor(uint128_t flags); + + /** + * @brief Constructor. + * + * @param selector, ist, flags, offset Copies the bits set from the given data into the individual components of + * a gate descriptor. + */ + gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset); + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(gate_descriptor const & other) const -> bool = default; + + private: + // The order in private variables starts for the first variable being the rightmost bit. + uint16_t _offset_1 = {}; ///< Lower 16 bits of handler function address (0 - 15) + segment_selector _selector = {}; ///< Segment selector (16 - 31) + ist_offset _ist = {}; ///< Interrupt Stack Table offset (32 - 39) + idt_flags _flags = {}; ///< Gate Type and Flags (40 - 47) + uint64_t _offset_2 : 48 = {}; ///< Upper 48 bits of handler function address (48 - 95) + uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp new file mode 100644 index 0000000..5104c36 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp @@ -0,0 +1,81 @@ + +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP + +#include <bitset> +#include <cstdint> + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Defines helper function for all states that the access byte field of a segment descriptor can + * have. + */ + struct [[gnu::packed]] idt_flags + { + /** + * @brief Possible set bits in our underlying bits and the meaning when they are set. + */ + enum bitset : uint8_t + { + INTERRUPT_GATE = 0b01110, ///< The actual type of gate segment is a interrupt gate. + TRAP_GATE = 0b01111, ///< The actual type of gate segment is a trap gate. + DESCRIPTOR_LEVEL_KERNEL = + 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. + DESCRIPTOR_LEVEL_ADMIN = + 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + DESCRIPTOR_LEVEL_PRIVILEGED_USER = + 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. + PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. + }; + + /** + * @brief Default Constructor. + */ + idt_flags() = default; + + /** + * @brief Constructor. + * + * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used + * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags + * are enabled or not using contains_flags method. + */ + idt_flags(uint8_t flags); + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * data. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying data has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying data. + */ + auto contains_flags(std::bitset<8U> other) const -> bool; + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(idt_flags const & other) const -> bool = default; + + /** + * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. + * + * @param other Additional bits that should be set. + */ + auto operator|=(std::bitset<8U> other) -> void; + + private: + uint8_t _flags = {}; ///< Underlying bits used to read the flags from. + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP
\ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp new file mode 100644 index 0000000..b388e0e --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp @@ -0,0 +1,24 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Updates the IDTR with the created interrupt descriptor table. If it has not been created yet this + * method will create it. + */ + auto update_interrupt_descriptor_table_register() -> void; + + /** + * @brief Creates the interrupt descriptor table, with the minimum required configuration. If this method is called + * more than once, the previously created instance is returned instead. + * + * @return Reference to the created interrupt_descriptor_table. + */ + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &; + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp new file mode 100644 index 0000000..7fe933b --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp @@ -0,0 +1,40 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" +#include "arch/stl/vector.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + using interrupt_descriptor_table = stl::vector<gate_descriptor>; + + /** + * @brief Represents a pointer to the Interrupt Descriptor Table (IDT). + * + * This structure is used to store the base address and length of the IDT. + */ + struct [[gnu::packed]] interrupt_descriptor_table_pointer + { + /** + * @brief Default constructor. + */ + interrupt_descriptor_table_pointer() = default; + + /** + * @brief Constructor. + */ + interrupt_descriptor_table_pointer(uint16_t table_length, gate_descriptor * address); + + /** + * @brief Defaulted three-way comparsion operator. + */ + auto operator<=>(interrupt_descriptor_table_pointer const & other) const -> std::strong_ordering = default; + + private: + uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. + gate_descriptor * address = {}; ///< Non-owning pointer to the IDT base address. + }; + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp new file mode 100644 index 0000000..e45bcf4 --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp @@ -0,0 +1,45 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP + +#include <bitset> +#include <cstdint> + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Defines helper function for all states that the interrupt stack table offset field of a gate descriptor can + * have. Is automatically increased to one byte in size, to include the following 5 reserved bits in the gate + * descriptor. + */ + struct [[gnu::packed]] ist_offset + { + /** + * @brief Default Constructor. + */ + ist_offset() = default; + + /** + * @brief Constructor. + * + * @param offset Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, whereas 1 - 7 + * mean we switch to the n-th stack in the Interrupt Stack Table, contained in the TSS if the gate descriptor that + * contains this field is called. + */ + ist_offset(uint8_t offset); + + /** + * @brief Allows to compare the underlying set bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(ist_offset const & other) const -> bool = default; + + private: + uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, + ///< whereas 1 - 7 mean we switch to the n-th stack in the Interrupt Stack Table, contained + ///< in the TSS if the gate descriptor that contains this field is called. + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp new file mode 100644 index 0000000..2a7704e --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp @@ -0,0 +1,105 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP + +#include <bitset> +#include <cstdint> + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + /** + * @brief Represents a segment selector in the x86_64 architecture, which points to a valid code segment in the global + * descriptor table. + * + * A segment selector is a 16-bit identifier used to select a segment descriptor + * from the Global Descriptor Table (GDT) or the Local Descriptor Table (LDT). + * It contains an index, a table indicator (TI), and a requested privilege level (RPL). + */ + struct [[gnu::packed]] segment_selector + { + /** + * @brief Possible set bits in our underlying bits and the meaning when they are set. + */ + enum bitset : uint8_t + { + REQUEST_LEVEL_KERNEL = + 0U << 0U, ///< Highest privileged level used by the kernel to allow for full access of resources. + REQUEST_LEVEL_ADMIN = + 1U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + REQUEST_LEVEL_PRIVILEGED_USER = + 2U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + REQUEST_LEVEL_USER = 3U << 0U, ///< Restricts access to only application and their specific memory. + LOCAL_DESCRIPTOR_TABLE = 1U << 2U, ///< Wheter the index referes to an entry in the local or global descriptor + ///< table. If enabled the index points to a local descriptor table, if it is + ///< cleared it referes to a global descriptor table instead. + }; + + /** + * @brief Default constructor. + */ + segment_selector() = default; + + /** + * @brief Constructor. + * + * @param index Index into the local or global descriptor table. Processor multiplies the index value by 8 (number + * of bytes in 32-bit segment descriptor) and adds the result to the base GDT or LDT address. + * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to + * allow for direct integer conversion. + */ + constexpr segment_selector(uint16_t index, uint8_t flags) + : _flags(flags) + , _index(index) + { + // Nothing to do. + } + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * data. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying data has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying data. + */ + auto contains_flags(std::bitset<3U> other) const -> bool; + + /** + * @brief Gets the index into the global descriptor table or the local descriptor table this segment selector is + * pointing too. + * + * @return Underlying value of the index field, bit 3 - 16. + */ + [[gnu::section(".user_text")]] + auto get_index() const -> uint16_t; + + /** + * @brief Defaulted three-way comparsion operator. + */ + auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; + + /** + * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. + * + * @param other Additional bits that should be set. + */ + auto operator|=(std::bitset<3U> other) -> void; + + /** + * @brief Cast the underlying data into a combined 16-bit form, that contains all data. + * + * @return Underlying value combined into it's full size. + */ + operator uint16_t() const; + + private: + uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. + uint16_t _index : 13 = + {}; ///< Index into the local or global descriptor table. Processor multiplies the index value by 16 (number of + ///< bytes in segment descriptor) and adds the result to the base address. + }; +} // namespace teachos::arch::context_switching::interrupt_descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/main.hpp b/arch/x86_64/pre/include/arch/context_switching/main.hpp new file mode 100644 index 0000000..f8477ea --- /dev/null +++ b/arch/x86_64/pre/include/arch/context_switching/main.hpp @@ -0,0 +1,51 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP + +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" + +namespace teachos::arch::context_switching +{ + /** + * @brief Contains the references to the tables required for context switching + */ + struct descriptor_tables + { + segment_descriptor_table::global_descriptor_table & gdt; ///< Reference to the global descriptor table. + interrupt_descriptor_table::interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. + }; + + /** + * @brief Creates the Interrupt Descriptor Table and Global Descriptor Table as a static variable the first time this + * method is called and update IDTR and GDTR registers values. + * + * @note Subsequent calls after the first one, will simply return the previously created tables, but not update the + * registers again. + * + * @return References to the statically created Interrupt Descriptor and Global Descriptor Table. + */ + auto initialize_descriptor_tables() -> descriptor_tables; + + /** + * @brief Switches from the current Kernel Mode (Level 0) to User Mode (Level 3). Will simply use predefined Segment + * Selectors for the User Data and User Code Segment, which are Index 3 and 4 in the GDT respectively. + */ + auto switch_to_user_mode() -> void; + + /** + * @brief Switches from the current Code and Data Segment to the given Code and Data Segment. + * + * @note This method will additionally call initialize_descriptor_tables, to ensure the GDTR and IDTR have been setup + * correctly before attempting to switch the context. This switch is achieved using a far return, which will once + * executed call the given void function. |
