diff options
| -rw-r--r-- | arch/x86_64/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp | 42 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/context_switching/descriptor_table/task_state_segment.hpp | 39 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/kernel/cpu/gdtr.hpp (renamed from arch/x86_64/include/arch/kernel/cpu/lgdt.hpp) | 6 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/kernel/cpu/tr.hpp | 26 | ||||
| -rw-r--r-- | arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp | 108 | ||||
| -rw-r--r-- | arch/x86_64/src/kernel/cpu/gdtr.cpp (renamed from arch/x86_64/src/kernel/cpu/lgdt.cpp) | 2 | ||||
| -rw-r--r-- | arch/x86_64/src/kernel/cpu/tr.cpp | 17 | ||||
| -rw-r--r-- | arch/x86_64/src/kernel/main.cpp | 1 |
9 files changed, 201 insertions, 43 deletions
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 <cstdint> + +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/lgdt.hpp b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp index 85e2949..f9220b9 100644 --- a/arch/x86_64/include/arch/kernel/cpu/lgdt.hpp +++ b/arch/x86_64/include/arch/kernel/cpu/gdtr.hpp @@ -1,5 +1,5 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP +#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" @@ -25,4 +25,4 @@ namespace teachos::arch::kernel::cpu } // namespace teachos::arch::kernel::cpu -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_LGDT_HPP +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_GDTR_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 <bitset> +#include <cstdint> + +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<segment_descriptor> 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<uint64_t>(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<segment_descriptor> 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<uint16_t>(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/lgdt.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp index 386914f..2fe3a99 100644 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ b/arch/x86_64/src/kernel/cpu/gdtr.cpp @@ -1,4 +1,4 @@ -#include "arch/kernel/cpu/lgdt.hpp" +#include "arch/kernel/cpu/gdtr.hpp" #include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" 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" |
