diff options
| author | Fabian Imhof <fabian.imhof@ost.ch> | 2025-03-20 15:30:18 +0000 |
|---|---|---|
| committer | Fabian Imhof <fabian.imhof@ost.ch> | 2025-03-20 15:30:18 +0000 |
| commit | b6ee8bec7ed23fd0c544f67f735e96b2bfe67682 (patch) | |
| tree | 1c738088d75bd7e1299d3b695e74e96d68878fc4 | |
| parent | 7a98b1dcb1f4436664a8f1a5d6e71ab2c65378f0 (diff) | |
| download | teachos-b6ee8bec7ed23fd0c544f67f735e96b2bfe67682.tar.xz teachos-b6ee8bec7ed23fd0c544f67f735e96b2bfe67682.zip | |
begin implementation of IDT
19 files changed, 310 insertions, 43 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index aad7951..a435ef9 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -9,6 +9,9 @@ target_sources("_kernel" PRIVATE "src/kernel/main.cpp" "src/kernel/cpu/control_register.cpp" "src/kernel/cpu/gdtr.cpp" + "src/kernel/cpu/idtr.cpp" + "src/kernel/cpu/if.cpp" + "src/kernel/cpu/jmp.cpp" "src/kernel/cpu/msr.cpp" "src/kernel/cpu/ss.cpp" "src/kernel/cpu/tlb.cpp" @@ -90,9 +93,13 @@ target_sources("_exception" PRIVATE target_sources("_context" PRIVATE "src/context_switching/descriptor_table/access_byte.cpp" + "src/context_switching/descriptor_table/gate_descriptor.cpp" "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/global_descriptor_table.cpp" "src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp" + "src/context_switching/descriptor_table/initialization.cpp" + "src/context_switching/descriptor_table/interrupt_descriptor_table.cpp" + "src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp" "src/context_switching/descriptor_table/segment_descriptor.cpp" ) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index fe9c657..2a43f22 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -10,6 +10,11 @@ namespace teachos::arch::boot */ extern "C" size_t const multiboot_information_pointer; + /** + * @brief Address pointing to the start of the multiboot information structure. + */ + extern "C" size_t const segment_register_reload_pointer; + } // namespace teachos::arch::boot #endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp new file mode 100644 index 0000000..f410219 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gate_descriptor.hpp @@ -0,0 +1,15 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP + +namespace teachos::arch::context_switching::descriptor_table +{ + struct [[gnu::packed]] gate_descriptor + { + /** + * @brief Default Constructor. + */ + gate_descriptor() = default; + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp new file mode 100644 index 0000000..c587000 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/initialization.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief TODO + * + */ + struct descriptor_tables + { + global_descriptor_table & gdt; ///< Reference to the global descriptor table. + interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. + }; + + auto initialize_descriptor_tables() -> descriptor_tables; + +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp new file mode 100644 index 0000000..c63932d --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP + +namespace teachos::arch::context_switching::descriptor_table +{ + struct interrupt_descriptor_table + { + }; + + auto initialize_interrupt_descriptor_table() -> void; + +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp new file mode 100644 index 0000000..e8935f4 --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp @@ -0,0 +1,42 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" +#include "arch/stl/vector.hpp" + +#include <cstdint> + +namespace teachos::arch::context_switching::descriptor_table +{ + typedef stl::vector<gate_descriptor> interrupt_descriptor_table; + + /** + * @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, interrupt_descriptor_table * 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. + interrupt_descriptor_table address = {}; ///< Non-owning pointer to the IDT base address. + }; + +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp new file mode 100644 index 0000000..724fbdf --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/idtr.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +#include <bitset> +#include <cstdint> + +namespace teachos::arch::kernel::cpu +{ + + /** + * @brief Returns the value in the IDTR register. + * + * @return Value of IDTR register. + */ + auto store_interrupt_descriptor_table() -> context_switching::descriptor_table::interrupt_descriptor_table_pointer; + + /** + * @brief Loads the interrupt_descriptor_table_pointer into the interrupt descriptor table register (IDTR). + */ + auto load_interrupt_descriptor_table( + context_switching::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/if.hpp b/arch/x86_64/include/arch/kernel/cpu/if.hpp new file mode 100644 index 0000000..51f5d9a --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/if.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Sets the interrupt flag (IF) in the EFLAGS register. + * This allows the processor to respond to maskable hardware interrupts. + */ + auto set_interrupt_flag() -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp new file mode 100644 index 0000000..666174c --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp @@ -0,0 +1,35 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP + +#include <cstdint> + +namespace teachos::arch::kernel::cpu +{ + /** + * @brief Far jump - A jump to an instruction located in a different segment. + */ + struct [[gnu::packed]] far_pointer + { + uint64_t offset; ///< Selector of the segment in which the jump occurs. + uint16_t segment; ///< Address to jump to within the segment. + }; + + /** + * @brief Near jump - A jump to an instruction within the current code segment. + * + * @param address to jump to. + */ + auto jmp(uint64_t address) -> void; + + /** + * @brief Far jump - A jump to an instruction located in a different segment than the current code segment but at the + * same privilege level. + * + * @param segment in which the jump occurs. + * @param offset to jump to. + */ + auto jmp(uint64_t segment, uint64_t offset) -> void; + +} // namespace teachos::arch::kernel::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 39bfe33..4fb23e5 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,7 +354,20 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +.global segment_register_reload_pointer +segment_register_reload_pointer: + xor %rax, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + + ret + _transition_to_long_mode: + call segment_register_reload_pointer + xor %rax, %rax mov %rax, %ss mov %rax, %ds diff --git a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp new file mode 100644 index 0000000..ee91e53 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp @@ -0,0 +1,5 @@ +#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ +} // namespace teachos::arch::context_switching::descriptor_table 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 dccce6b..639b079 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 @@ -38,8 +38,8 @@ namespace teachos::arch::context_switching::descriptor_table 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 code_segment{access_byte, gdt_flags, base, limit}; - return code_segment; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; } auto create_global_descriptor_table() -> global_descriptor_table @@ -53,6 +53,7 @@ namespace teachos::arch::context_switching::descriptor_table 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); @@ -85,44 +86,7 @@ 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."); - // Calculate the offset of the gdt in bytes to the TSS descriptor - uint16_t const tss_selector = (gdt.size() - 1) * sizeof(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."); return gdt; } - auto reload_cs_register(uint16_t gdt_data_offset) -> void - { - asm volatile("mov %[input], %%ax\n" - "mov %%ax %%ds\n" // Data Segment - "mov %%ax %%es\n" // Extra Segment (used for string operations) - "mov %%ax %%fs\n" // General-purpose Segment - "mov %%ax %%gs\n" // General-purpose Segment - "mov %%ax %%ss\n" // Stack Segment - : /* no output from call */ - : [input] "r"(gdt_data_offset) - : "ax"); - } - - auto reload_segment_register(uint16_t gdt_code_offset, uint16_t gdt_data_offset) -> void - { - /* - Whatever you do with the GDT has no effect on the CPU until you load new Segment Selectors into Segment Registers. - For most of these registers, the process is as simple as using MOV instructions, but changing the CS register - requires code resembling a jump or call to elsewhere, as this is the only way its value is meant to be changed. - */ - auto function = [gdt_data_offset] { reload_cs_register(gdt_data_offset); }; - - asm volatile("push %[input]\n" - "lea %[func], %%rax\n" - "push %%rax\n" - "retfq\n" - : /* no output from call */ - : [input] "r"(gdt_code_offset), [func] "r"(&function) - : "rax"); - } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp new file mode 100644 index 0000000..4d8b3e3 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp @@ -0,0 +1,38 @@ +#include "arch/context_switching/descriptor_table/initialization.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto initialize_descriptor_tables() -> descriptor_tables + { + decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + + // TODO: Replace random construction with return value of initialization. + interrupt_descriptor_table idt{}; + context_switching::descriptor_table::initialize_interrupt_descriptor_table(); + + kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + + uint16_t const tss_selector = (global_descriptor_table.size() - 1) << 3; + kernel::cpu::load_task_register(tss_selector); + + // Not sure if offset index or offset in bytes is needed! + // uint16_t const tss_selector = (gdt.size() - 1) * sizeof(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."); + + kernel::cpu::set_interrupt_flag(); + + descriptor_tables descriptor_tables = {global_descriptor_table, idt}; + return descriptor_tables; + } + +} // namespace teachos::arch::context_switching::descriptor_table
\ No newline at end of file diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp new file mode 100644 index 0000000..9878664 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto initialize_interrupt_descriptor_table() -> void + { + // DO NOT + } + +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp new file mode 100644 index 0000000..b45324d --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, + interrupt_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } + +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp new file mode 100644 index 0000000..bbf34cb --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/idtr.cpp @@ -0,0 +1,19 @@ +#include "arch/kernel/cpu/idtr.hpp" + +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::interrupt_descriptor_table_pointer current_value{}; + asm("sidt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto load_interrupt_descriptor_table( + context_switching::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void + { + asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp new file mode 100644 index 0000000..2a25df5 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/if.cpp @@ -0,0 +1,5 @@ +namespace teachos::arch::kernel::cpu +{ + auto set_interrupt_flag() -> void { asm volatile("sti"); } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp new file mode 100644 index 0000000..009981b --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -0,0 +1,16 @@ +#include "arch/kernel/cpu/jmp.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto jmp(uint64_t address) -> void + { + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); + } + + auto jmp(uint64_t segment, uint64_t offset) -> void + { + far_pointer far_pointer = {offset, static_cast<uint16_t>(segment)}; + asm volatile("jmp *%0" : : "m"(far_pointer)); + } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index da6d6d3..9433558 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,9 @@ #include "arch/kernel/main.hpp" -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/boot/pointers.hpp" +#include "arch/context_switching/descriptor_table/initialization.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,8 +63,7 @@ namespace teachos::arch::kernel heap_test(); - decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); - (void)global_descriptor_table.at(1); - video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); + decltype(auto) descriptor_tables = context_switching::descriptor_table::initialize_descriptor_tables(); + (void)descriptor_tables; } } // namespace teachos::arch::kernel |
