diff options
| author | Fabian Imhof <fabian.imhof@ost.ch> | 2025-03-16 12:41:09 +0000 |
|---|---|---|
| committer | Fabian Imhof <fabian.imhof@ost.ch> | 2025-03-16 12:41:09 +0000 |
| commit | 36758071881088b27a52cee4e5653f6cf6a79a78 (patch) | |
| tree | d427218710530eab7e007f6adca9fe4e1710250c /arch/x86_64/src/context_switching | |
| parent | 48578314c1e6af15f8cc1ce48df93e352a5a18ba (diff) | |
| download | teachos-36758071881088b27a52cee4e5653f6cf6a79a78.tar.xz teachos-36758071881088b27a52cee4e5653f6cf6a79a78.zip | |
start implementing TSS
Diffstat (limited to 'arch/x86_64/src/context_switching')
| -rw-r--r-- | arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp | 108 |
1 files changed, 71 insertions, 37 deletions
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 |
