aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp3
-rw-r--r--arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp12
-rw-r--r--arch/x86_64/include/arch/context_switching/segment_descriptor_table/gdt_flags.hpp15
-rw-r--r--arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp24
-rw-r--r--arch/x86_64/include/arch/kernel/cpu/jmp.hpp3
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp2
-rw-r--r--arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp31
-rw-r--r--arch/x86_64/src/context_switching/main.cpp23
-rw-r--r--arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp60
-rw-r--r--arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp2
-rw-r--r--arch/x86_64/src/kernel/cpu/jmp.cpp2
11 files changed, 100 insertions, 77 deletions
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp
index e677cbb..22cd0f0 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp
+++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp
@@ -61,8 +61,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
segment_selector _selector = {}; ///< Segment selector (16 - 31)
ist_offset _ist = {}; ///< Interrupt Stack Table offset (32 - 39)
idt_flags _flags = {}; ///< Gate Type and Flags (40 - 47)
- uint16_t _offset_2 = {}; ///< Middle 16 bits of handler function address (48 - 63)
- uint32_t _offset_3 = {}; ///< Upper 32 bits of handler function address (for x86_64) (64 - 95)
+ uint64_t _offset_2 : 48 = {}; ///< Upper 48 bits of handler function address (48 - 95)
uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127)
};
} // namespace teachos::arch::context_switching::interrupt_descriptor_table
diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp
index e2ec4c5..b388e0e 100644
--- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp
+++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp
@@ -6,12 +6,18 @@
namespace teachos::arch::context_switching::interrupt_descriptor_table
{
/**
- * @brief Initializes the interrupt_descriptor_table by loading it
- * in the IDTR register.
+ * @brief Updates the IDTR with the created interrupt descriptor table. If it has not been created yet this
+ * method will create it.
+ */
+ auto update_interrupt_descriptor_table_register() -> void;
+
+ /**
+ * @brief Creates the interrupt descriptor table, with the minimum required configuration. If this method is called
+ * more than once, the previously created instance is returned instead.
*
* @return Reference to the created interrupt_descriptor_table.
*/
- auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table &;
+ auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &;
} // namespace teachos::arch::context_switching::interrupt_descriptor_table
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 8217bcb..d8c3cd1 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,16 @@ namespace teachos::arch::context_switching::segment_descriptor_table
*/
enum bitset : uint8_t
{
- AVAILABLE = 1U << 0U, ///< Available for use by System software. For our purposes this is basically reserved.
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 this is set the DEFAULT_OPERAND_SIZE/BIG bit needs to be clear (0).
-
- DEFAULT_OPERATION_SIZE =
- 1U << 2U, ///< If clear, this is a 16-bit code segment; if set, this is a 32-bit segment.
- BIG = 1U << 2U, ///< If set, the maximum offset size for a data segment is increased to 32-bit
- ///< 0xffffffff. Otherwise it's the 16-bit max 0x0000ffff. Essentially the same meaning as "D".
-
+ ///< If this bit is set the 3rd bit needs to be clear (0).
+ UPPER_BOUND = 1U << 2U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 4
+ ///< GiB, 4 KiB otherwise.
+ STACK_POINTER_SIZE = 1U << 2U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for
+ ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise.
+ DEFAULT_LENGTH = 1U << 2U, ///< Indicates the default length for code segments with effective addresses and
+ ///< operands. Enable for 32 bit, 16 bit otherwise.
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.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp
index f3067ba..bd69a46 100644
--- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp
+++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp
@@ -7,12 +7,30 @@
namespace teachos::arch::context_switching::segment_descriptor_table
{
/**
- * @brief Initializes the global_descriptor_table and task_state_segment by loading them
- * in the GDTR and TR registers respectively.
+ * @brief Creates the global descriptor table, with the minimum required configuration. If this method is called more
+ * than once, the previously created instance is returned instead.
*
* @return Reference to the created global_descriptor_table.
*/
- auto initialize_global_descriptor_table() -> global_descriptor_table &;
+ auto get_or_create_global_descriptor_table() -> global_descriptor_table &;
+
+ /**
+ * @brief Updates the GDTR with the created global descriptor table. If it has not been created yet this
+ * method will create it.
+ *
+ * @note This method will only set the GDTR, but for the processor to actually register the change a far jump
+ * has to be executed. This also has to be done before updating the TR.
+ */
+ auto update_global_descriptor_table_register() -> void;
+
+ /**
+ * @brief Updates the TR with the created task state segment. If it has not been created yet this
+ * method will create it.
+ *
+ * @note This method should only be called after update_global_descriptor_table_register() and a far jump has been
+ * executed. Because before that trying to access the segment will cause an exception.
+ */
+ auto update_task_state_segment_register() -> void;
} // 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 0ed38e9..1657c18 100644
--- a/arch/x86_64/include/arch/kernel/cpu/jmp.hpp
+++ b/arch/x86_64/include/arch/kernel/cpu/jmp.hpp
@@ -13,7 +13,8 @@ namespace teachos::arch::kernel::cpu
struct far_pointer
{
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)
+ context_switching::interrupt_descriptor_table::segment_selector
+ selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79)
};
/**
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 d86c459..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
@@ -8,7 +8,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
, _ist(flags >> 32U)
, _flags(flags >> 40U)
, _offset_2(flags >> 48U)
- , _offset_3(flags >> 64U)
{
// Nothing to do.
}
@@ -19,7 +18,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table
, _ist(ist)
, _flags(flags)
, _offset_2(offset >> 16U)
- , _offset_3(offset >> 48U)
{
// Nothing to do.
}
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 1c1de68..62b116b 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
@@ -6,26 +6,23 @@
namespace teachos::arch::context_switching::interrupt_descriptor_table
{
- namespace
+ auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &
{
+ // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0)
+ uint64_t offset = reinterpret_cast<uint64_t>(&interrupt_handling::generic_interrupt_handler);
+ segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL};
+ ist_offset ist{0U};
+ idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT};
+ gate_descriptor descriptor{selector, ist, flags, offset};
- auto create_interrupt_descriptor_table() -> interrupt_descriptor_table
- {
- // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0)
- uint64_t offset = reinterpret_cast<uint64_t>(&interrupt_handling::generic_interrupt_handler);
- segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL};
- ist_offset ist{0U};
- idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT};
- gate_descriptor descriptor{selector, ist, flags, offset};
-
- return interrupt_descriptor_table{descriptor};
- }
- } // namespace
+ // Interrupt Descriptor Table needs to be kept alive
+ static interrupt_descriptor_table interrupt_descriptor_table{descriptor};
+ return interrupt_descriptor_table;
+ }
- auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table &
+ auto update_interrupt_descriptor_table_register() -> void
{
- // Interrupt Descriptor Table needs to be kept alive
- static auto idt = create_interrupt_descriptor_table();
+ static auto idt = get_or_create_interrupt_descriptor_table();
interrupt_descriptor_table_pointer idt_pointer{static_cast<uint16_t>((idt.size() * sizeof(gate_descriptor)) - 1),
idt.data()};
@@ -35,7 +32,5 @@ namespace teachos::arch::context_switching::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/main.cpp b/arch/x86_64/src/context_switching/main.cpp
index 008da2f..db04b52 100644
--- a/arch/x86_64/src/context_switching/main.cpp
+++ b/arch/x86_64/src/context_switching/main.cpp
@@ -11,22 +11,16 @@ namespace teachos::arch::context_switching
auto initialize_descriptor_tables() -> descriptor_tables
{
kernel::cpu::clear_interrupt_flag();
- decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table();
- decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table();
- 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));
+ segment_descriptor_table::update_global_descriptor_table_register();
+ interrupt_descriptor_table::update_interrupt_descriptor_table_register();
- // 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);
+ interrupt_descriptor_table::segment_selector segment_selector{
+ 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL};
+ kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector};
+ kernel::cpu::jmp(pointer);
- 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.");
+ segment_descriptor_table::update_task_state_segment_register();
// FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP
// and triple fault.
@@ -34,7 +28,8 @@ namespace teachos::arch::context_switching
// idt). NEVER happened when stepping through quickly. Can you reproduce this?
kernel::cpu::set_interrupt_flag();
- descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table};
+ descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(),
+ interrupt_descriptor_table::get_or_create_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 d9ad91c..346db9e 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
@@ -24,7 +24,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table
}
else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT)
{
- gdt_flags_bits |= 1 << 2;
+ gdt_flags_bits |= gdt_flags::UPPER_BOUND;
access_level_bits |= access_byte::WRITABLE;
}
@@ -46,33 +46,33 @@ namespace teachos::arch::context_switching::segment_descriptor_table
TSS_LIMIT};
return tss_descriptor;
}
+ } // namespace
- 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);
+ auto get_or_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);
- // 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);
+ // 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);
- 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
+ // Global Descriptor Table needs to be kept alive
+ static global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment,
+ user_code_segment, user_data_segment, tss_descriptor};
+ return global_descriptor_table;
+ }
- auto initialize_global_descriptor_table() -> global_descriptor_table &
+ auto update_global_descriptor_table_register() -> void
{
- // Global Descriptor Table needs to be kept alive
- static auto gdt = create_global_descriptor_table();
+ decltype(auto) gdt = get_or_create_global_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.
@@ -84,8 +84,20 @@ namespace teachos::arch::context_switching::segment_descriptor_table
arch::exception_handling::assert(
gdt_pointer == stored_gdt_pointer,
"[Global Descriptor Table] Loaded GDTR value is not the same as the stored value.");
+ }
+
+ auto update_task_state_segment_register() -> void
+ {
+ decltype(auto) gdt = get_or_create_global_descriptor_table();
+
+ // 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 = (gdt.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor);
+ kernel::cpu::load_task_register(tss_selector);
- return gdt;
+ 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.");
}
} // namespace teachos::arch::context_switching::segment_descriptor_table
diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp
index 68b4568..2f599e5 100644
--- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp
+++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp
@@ -11,4 +11,4 @@ namespace teachos::arch::interrupt_handling
(void)frame;
video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black);
}
-} // namespace teachos::arch::interrupt_handling \ No newline at end of file
+} // namespace teachos::arch::interrupt_handling
diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp
index 0c94693..2833219 100644
--- a/arch/x86_64/src/kernel/cpu/jmp.cpp
+++ b/arch/x86_64/src/kernel/cpu/jmp.cpp
@@ -9,6 +9,6 @@ namespace teachos::arch::kernel::cpu
auto jmp(far_pointer pointer) -> void
{
- asm volatile("rex64 ljmp *%[input]" : /* no output from call */ : [input] "m"(pointer));
+ asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer));
}
} // namespace teachos::arch::kernel::cpu