aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp31
1 files changed, 31 insertions, 0 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 578e264..dccce6b 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
@@ -94,4 +94,35 @@ namespace teachos::arch::context_switching::descriptor_table
"[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