aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src/context_switching
diff options
context:
space:
mode:
authorMatteo Gmür <matteo.gmuer1@ost.ch>2025-03-25 16:58:24 +0000
committerMatteo Gmür <matteo.gmuer1@ost.ch>2025-03-25 16:58:24 +0000
commit66fefaeb16bcbc4eae5ce5256ae76f51a155cded (patch)
tree121b05b3764c7825f4f87c43e0bce6dd32707d29 /arch/x86_64/src/context_switching
parentccb47845d99e098c183f596cd1a3eb1db5c676da (diff)
downloadteachos-66fefaeb16bcbc4eae5ce5256ae76f51a155cded.tar.xz
teachos-66fefaeb16bcbc4eae5ce5256ae76f51a155cded.zip
Implement idtr structure and document possible flags.
Diffstat (limited to 'arch/x86_64/src/context_switching')
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp19
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp15
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp24
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp10
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp16
-rw-r--r--arch/x86_64/src/context_switching/main.cpp7
-rw-r--r--arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp105
-rw-r--r--arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp10
8 files changed, 139 insertions, 67 deletions
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<uint16_t>(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<uint8_t *>(&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<uint64_t>(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<uint64_t>(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.
}