diff options
| author | Fabian Imhof <fabian.imhof@ost.ch> | 2025-03-29 09:30:50 +0100 |
|---|---|---|
| committer | Fabian Imhof <fabian.imhof@ost.ch> | 2025-03-29 09:30:50 +0100 |
| commit | 98be1b722f17e77880e8c0b0f464a9ba31230fc4 (patch) | |
| tree | aa693a6f6edc717a1f3e184141d0ee1c150c57d7 | |
| parent | 437c3554f9a86b6347d97f5e2a82543c1e068b05 (diff) | |
| parent | fbd1ebe4f7c5985554fdca7c7fc05de15d47dd3a (diff) | |
| download | teachos-98be1b722f17e77880e8c0b0f464a9ba31230fc4.tar.xz teachos-98be1b722f17e77880e8c0b0f464a9ba31230fc4.zip | |
Merge branch 'fmorgner/patch-context-switching' into 'feat_inital_context_switching'
Fix GDT and CS reload
See merge request teachos/kernel!5
9 files changed, 42 insertions, 29 deletions
diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2e076e4..6fc5711 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -10,6 +10,9 @@ "-s", "-m", "32M", + "-no-reboot", + "-d", + "int,cpu_reset", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" ], 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<uint16_t>((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) { |
