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/x86_64') 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