From ccb47845d99e098c183f596cd1a3eb1db5c676da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 25 Mar 2025 12:04:43 +0000 Subject: Adjust file structure and fix compilation issues --- arch/x86_64/src/context_switching/main.cpp | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 arch/x86_64/src/context_switching/main.cpp (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp new file mode 100644 index 0000000..b682e79 --- /dev/null +++ b/arch/x86_64/src/context_switching/main.cpp @@ -0,0 +1,36 @@ +#include "arch/context_switching/main.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 +{ + 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(); + + kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_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); + + 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 tables = {global_descriptor_table, idt}; + return tables; + } +} // namespace teachos::arch::context_switching -- cgit v1.2.3 From 66fefaeb16bcbc4eae5ce5256ae76f51a155cded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 25 Mar 2025 16:58:24 +0000 Subject: Implement idtr structure and document possible flags. --- arch/x86_64/src/context_switching/main.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') 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 -- cgit v1.2.3 From a6c5f6a273d0c5c4161f600fca6d4fe49858c23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 27 Mar 2025 09:40:32 +0000 Subject: Attempt to fix crash in far jump. WIP does not return from call to assembler method --- arch/x86_64/src/context_switching/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 95a25e0..c3c0cf0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,7 +13,10 @@ 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(); - kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + interrupt_descriptor_table::segment_selector segment_selector{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::jmp(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 -- cgit v1.2.3 From 9ddfcd02413a93718e8cde53f9ba5a96a5b29b8f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Mar 2025 14:02:05 +0000 Subject: update long jump handling --- arch/x86_64/src/context_switching/main.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c3c0cf0..1417a25 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,10 +13,8 @@ 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::segment_register_reload_pointer, segment_selector}; - kernel::cpu::jmp(pointer); + // Execute trampoline function for the GDT loading long jump + boot::reload_segment_register_trampoline(); // 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 -- cgit v1.2.3 From e0eae9b9e905a1842b333823bfdb7c253cda8d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 28 Mar 2025 09:59:09 +0000 Subject: Revert "update long jump handling" This reverts commit 9ddfcd02413a93718e8cde53f9ba5a96a5b29b8f. --- arch/x86_64/src/context_switching/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 1417a25..c3c0cf0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,8 +13,10 @@ 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(); - // Execute trampoline function for the GDT loading long jump - boot::reload_segment_register_trampoline(); + interrupt_descriptor_table::segment_selector segment_selector{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::jmp(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 -- cgit v1.2.3 From 437c3554f9a86b6347d97f5e2a82543c1e068b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 28 Mar 2025 10:52:25 +0000 Subject: Attempt to fix ljmp. Might not be possible in Long mode --- arch/x86_64/src/context_switching/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c3c0cf0..5d19f23 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -15,7 +15,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::far_pointer pointer{boot::reload_segment_register, segment_selector}; kernel::cpu::jmp(pointer); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating -- cgit v1.2.3 From fbd1ebe4f7c5985554fdca7c7fc05de15d47dd3a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Mar 2025 18:35:28 +0100 Subject: gdt: fix reload of GDT The core problems were/are the following: - The flags of the segments were not entirely correct. Please recheck them against the spec! - The GDT pointer did not contain the address of the first (null) GTD entry, but the address of the stl::vector containing the GDT entries. - The far pointer must consist of: - the address to jump to - the byte index into the GDT for the desired segement descriptor to be loaded into CS. - The type of the "dummy" function we jump to was wrong (it's a function, we should declare it as such). - We cannot enable interrupts right now, since we die with a triple fault. This is caused by some initia fault which seems to lead to a general protection fault, which then triple faults since we cannot find the IDT. Some FIXMEs have been added to the code. Please look at them carefully and compare things against the specs. --- arch/x86_64/src/context_switching/main.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') 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; -- cgit v1.2.3 From aba154ad01fc0e1e1274f2582b1493e78daa2559 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 29 Mar 2025 14:47:04 +0000 Subject: fix gdt segments, improve idt and trial&error for triple fault --- arch/x86_64/src/context_switching/main.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index a5bd3fb..f449a3a 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -10,24 +10,30 @@ 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)); + 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."); - // 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(); + // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP + // and triple fault. + + // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the + // 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}; return tables; -- cgit v1.2.3 From 8d16dcb672c4b5f4b0a12ef2eac3486f1b2bb316 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 29 Mar 2025 14:47:23 +0000 Subject: remove empty line --- arch/x86_64/src/context_switching/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index f449a3a..008da2f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -30,7 +30,6 @@ namespace teachos::arch::context_switching // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. - // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); -- cgit v1.2.3 From abe7bd7480c8f4e1e30b9f0f3b98966222817f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 10:38:53 +0000 Subject: Clean up global descriptor table initalization --- arch/x86_64/src/context_switching/main.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') 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 -- cgit v1.2.3 From e8fb1d771d9aa4d1cb5b18cd0483c7e5731aeecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 13:18:56 +0000 Subject: Improve create_segment readability --- arch/x86_64/src/context_switching/main.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index db04b52..2b853ec 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -24,8 +24,6 @@ namespace teachos::arch::context_switching // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. - // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the - // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), -- cgit v1.2.3 From fc4a2306b803ccfc27f1bdc4a831176a5278a9d5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 2 Apr 2025 09:57:54 +0000 Subject: fix interrupt handler and idt --- arch/x86_64/src/context_switching/main.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 2b853ec..ac53735 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -22,8 +22,6 @@ namespace teachos::arch::context_switching 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. kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), -- cgit v1.2.3 From 8b66e4cd1d1487fefbae459f556396db61497a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 4 Apr 2025 15:05:59 +0000 Subject: Multiplication by two for segment selector index --- arch/x86_64/src/context_switching/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index ac53735..6614065 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -16,7 +16,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::update_interrupt_descriptor_table_register(); interrupt_descriptor_table::segment_selector segment_selector{ - 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; kernel::cpu::jmp(pointer); -- cgit v1.2.3 From a8852f91967a7e55e62e30f5cc07d076092b8b78 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 5 Apr 2025 15:27:20 +0000 Subject: add wip context switch to user mode --- arch/x86_64/src/context_switching/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 6614065..124df93 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,9 +1,9 @@ #include "arch/context_switching/main.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/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" namespace teachos::arch::context_switching @@ -17,7 +17,7 @@ namespace teachos::arch::context_switching 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::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; kernel::cpu::jmp(pointer); segment_descriptor_table::update_task_state_segment_register(); -- cgit v1.2.3 From 8a23a47425162894141f4eac488fb1f1bb3f7dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 7 Apr 2025 15:42:38 +0000 Subject: Fix naming from jmp to call for Far Call --- arch/x86_64/src/context_switching/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 124df93..762445f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,8 +1,8 @@ #include "arch/context_switching/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -18,7 +18,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; - kernel::cpu::jmp(pointer); + kernel::cpu::call(pointer); segment_descriptor_table::update_task_state_segment_register(); -- cgit v1.2.3 From dff78de795a89c181e9c94b26db2f16988e8f4d6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 12:11:55 +0000 Subject: move context_switch function and environment into different directory --- arch/x86_64/src/context_switching/main.cpp | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 762445f..3efba45 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -5,9 +5,59 @@ #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" +#include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching { + namespace + { + + /** + * @brief Switch context into the mode defined in the segment selectors. + * + * Setup the stack IRETQ expects to switch the mode: + * 1. push data selector + * 2. push current stack pointer + * 3. push eflags + * 4. push code segment selector + * 5. push return address + * + * @param data_segment + * @param code_segment + * @param address + */ + [[gnu::naked]] + auto far_return(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) + -> void + { + asm volatile("mov %[data_segment], %%rax\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "mov %%rsp, %%rax\n" + + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" + + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); + } + + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + + } // namespace + auto initialize_descriptor_tables() -> descriptor_tables { kernel::cpu::clear_interrupt_flag(); @@ -28,4 +78,26 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } + + auto user_mode_main() -> void + { + auto current_segment = kernel::cpu::read_code_segment_register(); + arch::exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, + "[Context Switching] Context switch into user mode not successful"); + + video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); + } + + auto switch_to_user_mode() -> void + { + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); + } + + auto switch_context(interrupt_descriptor_table::segment_selector data_segment, + interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void + { + kernel::cpu::set_segment_registers(data_segment); + far_return(data_segment, code_segment, reinterpret_cast(return_function)); + } + } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 87091e2246d2c4c794d9d6a0c5398ca80d92335a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 12:29:19 +0000 Subject: add register validation and asserts --- arch/x86_64/src/context_switching/main.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 3efba45..0f2ec93 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -2,6 +2,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" +#include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -82,10 +83,12 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { auto current_segment = kernel::cpu::read_code_segment_register(); - arch::exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, - "[Context Switching] Context switch into user mode not successful"); + exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, + "[Context Switching] Context switch into user mode not successful"); + exception_handling::assert(USER_DATA_SEGMENT_SELECTOR == kernel::cpu::validate_data_segment_registers(), + "[Context Switching] Context switch into user mode not successful"); - video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } auto switch_to_user_mode() -> void -- cgit v1.2.3 From 9a185c1533bd2197d0e830369b4cc26abf88e2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 09:25:04 +0000 Subject: Document methods and move them into kernel cpu folder --- arch/x86_64/src/context_switching/main.cpp | 63 +++++++----------------------- 1 file changed, 14 insertions(+), 49 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 0f2ec93..5cac878 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -12,46 +12,6 @@ namespace teachos::arch::context_switching { namespace { - - /** - * @brief Switch context into the mode defined in the segment selectors. - * - * Setup the stack IRETQ expects to switch the mode: - * 1. push data selector - * 2. push current stack pointer - * 3. push eflags - * 4. push code segment selector - * 5. push return address - * - * @param data_segment - * @param code_segment - * @param address - */ - [[gnu::naked]] - auto far_return(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) - -> void - { - asm volatile("mov %[data_segment], %%rax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - "mov %%rsp, %%rax\n" - - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - - "iretq\n" - : - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ @@ -61,6 +21,14 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { + static bool initalized = false; + if (initalized) + { + descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + return tables; + } + kernel::cpu::clear_interrupt_flag(); segment_descriptor_table::update_global_descriptor_table_register(); @@ -68,7 +36,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; + kernel::cpu::far_pointer pointer{&kernel::cpu::reload_data_segment_registers, segment_selector}; kernel::cpu::call(pointer); segment_descriptor_table::update_task_state_segment_register(); @@ -77,17 +45,13 @@ namespace teachos::arch::context_switching descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + initalized = true; return tables; } auto user_mode_main() -> void { - auto current_segment = kernel::cpu::read_code_segment_register(); - exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, - "[Context Switching] Context switch into user mode not successful"); - exception_handling::assert(USER_DATA_SEGMENT_SELECTOR == kernel::cpu::validate_data_segment_registers(), - "[Context Switching] Context switch into user mode not successful"); - + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } @@ -99,8 +63,9 @@ namespace teachos::arch::context_switching auto switch_context(interrupt_descriptor_table::segment_selector data_segment, interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void { - kernel::cpu::set_segment_registers(data_segment); - far_return(data_segment, code_segment, reinterpret_cast(return_function)); + (void)initialize_descriptor_tables(); + kernel::cpu::set_data_segment_registers(data_segment); + kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 0c75a6ef8e47106e7fc51ca5e11eb4116e879e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 10:50:03 +0000 Subject: Improve initialize_descriptor_tables --- arch/x86_64/src/context_switching/main.cpp | 31 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5cac878..952a3b2 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -12,6 +12,10 @@ namespace teachos::arch::context_switching { namespace { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, + KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ @@ -22,30 +26,23 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { static bool initalized = false; - if (initalized) - { - descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), - interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - return tables; - } - - kernel::cpu::clear_interrupt_flag(); - segment_descriptor_table::update_global_descriptor_table_register(); - interrupt_descriptor_table::update_interrupt_descriptor_table_register(); + if (!initalized) + { + kernel::cpu::clear_interrupt_flag(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&kernel::cpu::reload_data_segment_registers, segment_selector}; - kernel::cpu::call(pointer); + segment_descriptor_table::update_global_descriptor_table_register(); + interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - segment_descriptor_table::update_task_state_segment_register(); + kernel::cpu::call(KERNEL_CODE_POINTER); + segment_descriptor_table::update_task_state_segment_register(); - kernel::cpu::set_interrupt_flag(); + kernel::cpu::set_interrupt_flag(); + initalized = true; + } descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - initalized = true; return tables; } -- cgit v1.2.3 From eafe8533bb5ccbe15bd8ffbc917b38122b04a157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Apr 2025 15:21:52 +0000 Subject: Add stack frame allocator. Fix stl vector bug and create stl stack implementation --- arch/x86_64/src/context_switching/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 952a3b2..486a09f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -21,6 +21,8 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -34,7 +36,7 @@ namespace teachos::arch::context_switching segment_descriptor_table::update_global_descriptor_table_register(); interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - kernel::cpu::call(KERNEL_CODE_POINTER); + reload_global_descriptor_table_register(); segment_descriptor_table::update_task_state_segment_register(); kernel::cpu::set_interrupt_flag(); -- cgit v1.2.3 From 576a7a95b2462ec4938de9fe344657ca04b2ba34 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 17 Apr 2025 14:14:49 +0000 Subject: add syscall interrupt handler --- arch/x86_64/src/context_switching/main.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 952a3b2..fc8790f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -49,6 +49,9 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + asm volatile("INT $0x80"); + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 0986058bb9ca5b4afd7c578c815dc3a4c08808a9 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Mon, 21 Apr 2025 08:18:41 +0000 Subject: WIP syscall --- arch/x86_64/src/context_switching/main.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7be286a..faaf831 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -52,7 +52,14 @@ namespace teachos::arch::context_switching { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - asm volatile("INT $0x80"); + // TODO/INFO: + // https://stackoverflow.com/questions/46022184/osdev-syscall-sysret-and-sysenter-sysexit-instructions-enabling + // https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall-in-32-bit-code-on-linux + // + // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! + + // asm volatile("INT $0x80"); + asm volatile("SYSCALL"); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From c865eff02ae1978b4f665432d853374d1ffacecf Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 10:21:29 +0000 Subject: create trampoline for syscall --- arch/x86_64/src/context_switching/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index faaf831..c949488 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,5 +1,6 @@ #include "arch/context_switching/main.hpp" +#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -59,7 +60,8 @@ namespace teachos::arch::context_switching // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! // asm volatile("INT $0x80"); - asm volatile("SYSCALL"); + // asm volatile("SYSCALL"); + boot::syscall_trampoline(); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 7261c64bb236a313ed8846a9c9dbded6890a9e98 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 11:20:02 +0000 Subject: wip implement syscall in cpp --- arch/x86_64/src/context_switching/main.cpp | 43 +++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c949488..85cefe5 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,6 +1,7 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall_handler.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -53,15 +54,7 @@ namespace teachos::arch::context_switching { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - // TODO/INFO: - // https://stackoverflow.com/questions/46022184/osdev-syscall-sysret-and-sysenter-sysexit-instructions-enabling - // https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall-in-32-bit-code-on-linux - // - // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! - - // asm volatile("INT $0x80"); - // asm volatile("SYSCALL"); - boot::syscall_trampoline(); + asm volatile("SYSCALL"); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } @@ -79,4 +72,36 @@ namespace teachos::arch::context_switching kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } + auto setup_syscall() -> void + { + uint64_t handler = reinterpret_cast(syscall_handler); + asm volatile( + /* Write syscall_handler pointer in IA32_LSTAR MSR */ + "mov $0xC0000082, %%ecx\n" /* IA32_LSTAR MSR */ + "mov %[syscall_handler], %%rax" + "mov %[syscall_handler], %%rdx" + "shr $32, %%rdx\n" + "wrmsr\n" + + /* Write RFLAGS Mask in IA32_LSTAR MSR */ + "mov $0xC0000084, %%ecx\n" /* IA32_FMASK MSR */ + "mov $0x0, %%rax\n" /* RFLAGS Mask lower 32 bits */ + "mov $0x0, %%rdx\n" /* RFLAGS Mask upper 32 bits */ + "wrmsr\n" + + /* Write kernel code segment offset in IA32_STAR MSR */ + "mov $0xC0000081, %%ecx\n" /* IA32_STAR MSR */ + "mov $0x10, %%rax\n" /* kernel code segment offset lower 32 bits */ + "mov $0x0, %%rdx\n" /* kernel code segment offset upper 32 bits */ + "wrmsr\n" + + /* Set SCE bit in MSR_EFER (enabling syscall instruction)*/ + "mov $0xC0000080, %%ecx\n" + "rdmsr\n" + "or $0x1, %%eax\n" + "wrmsr" + : /* no output from call */ + : [syscall_handler] "r"(handler)); + } + } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 187eba4eca3ea46d8c26419168e525242338dae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 13:18:49 +0000 Subject: Simplify syscall setup --- arch/x86_64/src/context_switching/main.cpp | 40 +++++++++--------------------- 1 file changed, 12 insertions(+), 28 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 85cefe5..155d150 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -6,6 +6,7 @@ #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/msr.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/video/vga/text.hpp" @@ -14,6 +15,10 @@ namespace teachos::arch::context_switching { namespace { + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, @@ -74,34 +79,13 @@ namespace teachos::arch::context_switching auto setup_syscall() -> void { - uint64_t handler = reinterpret_cast(syscall_handler); - asm volatile( - /* Write syscall_handler pointer in IA32_LSTAR MSR */ - "mov $0xC0000082, %%ecx\n" /* IA32_LSTAR MSR */ - "mov %[syscall_handler], %%rax" - "mov %[syscall_handler], %%rdx" - "shr $32, %%rdx\n" - "wrmsr\n" - - /* Write RFLAGS Mask in IA32_LSTAR MSR */ - "mov $0xC0000084, %%ecx\n" /* IA32_FMASK MSR */ - "mov $0x0, %%rax\n" /* RFLAGS Mask lower 32 bits */ - "mov $0x0, %%rdx\n" /* RFLAGS Mask upper 32 bits */ - "wrmsr\n" - - /* Write kernel code segment offset in IA32_STAR MSR */ - "mov $0xC0000081, %%ecx\n" /* IA32_STAR MSR */ - "mov $0x10, %%rax\n" /* kernel code segment offset lower 32 bits */ - "mov $0x0, %%rdx\n" /* kernel code segment offset upper 32 bits */ - "wrmsr\n" - - /* Set SCE bit in MSR_EFER (enabling syscall instruction)*/ - "mov $0xC0000080, %%ecx\n" - "rdmsr\n" - "or $0x1, %%eax\n" - "wrmsr" - : /* no output from call */ - : [syscall_handler] "r"(handler)); + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + uint64_t const segment_selector = *reinterpret_cast(&KERNEL_CODE_SEGMENT_SELECTOR); + + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, segment_selector); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 13dd2bd5a88ec7efeadf8586778f2c5a26d8cd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 14:07:33 +0000 Subject: Move not public methods into anonymous namespace --- arch/x86_64/src/context_switching/main.cpp | 59 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 155d150..f73cb19 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,7 +1,6 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall_handler.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -30,6 +29,43 @@ namespace teachos::arch::context_switching auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + auto user_mode_main() -> void + { + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + + asm volatile("syscall"); + + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRET!", + video::vga::text::common_attributes::green_on_black); + } + + auto syscall_handler() -> void + { + uint64_t dummy{}; + switch (dummy) + { + case 0: + break; + default: + break; + } + + asm volatile("sysretq"); + } + + auto enable_systemcall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } + } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -55,17 +91,9 @@ namespace teachos::arch::context_switching return tables; } - auto user_mode_main() -> void - { - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - - asm volatile("SYSCALL"); - - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); - } - auto switch_to_user_mode() -> void { + enable_systemcall(); switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); } @@ -77,15 +105,4 @@ namespace teachos::arch::context_switching kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } - auto setup_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - uint64_t const segment_selector = *reinterpret_cast(&KERNEL_CODE_SEGMENT_SELECTOR); - - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, segment_selector); - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - } // namespace teachos::arch::context_switching -- cgit v1.2.3 From a8a8e09ed39268839ca838c44489bb1352892fef Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 14:11:43 +0000 Subject: merge --- arch/x86_64/src/context_switching/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index f73cb19..287ced4 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -104,5 +104,4 @@ namespace teachos::arch::context_switching kernel::cpu::set_data_segment_registers(data_segment); kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } - } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 7c5a40a0de0c5e3ce0a51aa5414c4a433190c60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 14:17:19 +0000 Subject: Add validate methods. For WIP systemcall --- arch/x86_64/src/context_switching/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 287ced4..bd48e18 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -20,6 +20,8 @@ namespace teachos::arch::context_switching constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + constexpr interrupt_descriptor_table::segment_selector KERNEL_DATA_SEGMENT_SELECTOR{ + 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ @@ -45,6 +47,8 @@ namespace teachos::arch::context_switching auto syscall_handler() -> void { + kernel::cpu::validate_segment_registers(KERNEL_CODE_SEGMENT_SELECTOR, KERNEL_DATA_SEGMENT_SELECTOR); + uint64_t dummy{}; switch (dummy) { -- cgit v1.2.3 From 95c299db969b29eb4a4742ff7715adecfe138bd5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 14:43:31 +0000 Subject: test different values --- arch/x86_64/src/context_switching/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 287ced4..4e13b1c 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -62,7 +62,16 @@ namespace teachos::arch::context_switching uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // Your 64-bit kernel code segment selector + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR + 0x3; // User mode code segment selector (RPL=3) + + uint64_t star_value = (user_cs << 48) | (kernel_cs << 32); + + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); + + // kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -- cgit v1.2.3 From adb66c18b9e6ca0f65934f453afda1c5f9fe145f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 15:14:04 +0000 Subject: wip enable syscall --- arch/x86_64/src/context_switching/main.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 33af765..21299da 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -33,22 +33,16 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); asm volatile("syscall"); - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - - video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRET!", + video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } auto syscall_handler() -> void { - kernel::cpu::validate_segment_registers(KERNEL_CODE_SEGMENT_SELECTOR, KERNEL_DATA_SEGMENT_SELECTOR); - uint64_t dummy{}; switch (dummy) { @@ -65,17 +59,19 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // Your 64-bit kernel code segment selector - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR + 0x3; // User mode code segment selector (RPL=3) - - uint64_t star_value = (user_cs << 48) | (kernel_cs << 32); - + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall + + // @MTO: This produces following values: + // After SYSCALL: CS = 0x10, SS = 0x18 + // After SYSRETQ: CS = 0x43, SS = 0x3b + // + // We probably need to modify our GDT, because the cs+8 = ss is an issue we cannot solve. + // Also, CS = 0x43 is weird. I expected it to be 0x33. + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR; + uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); - // kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -- cgit v1.2.3 From ecdfbc3e1458923f619f0d4b8a841a6e96a6678a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Apr 2025 15:01:44 +0000 Subject: Start adding parameters to syscall --- arch/x86_64/src/context_switching/main.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 21299da..2a2a188 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -35,6 +35,11 @@ namespace teachos::arch::context_switching { video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + uint64_t new_value = 60U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); asm volatile("syscall"); video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", @@ -43,10 +48,16 @@ namespace teachos::arch::context_switching auto syscall_handler() -> void { - uint64_t dummy{}; - switch (dummy) + uint64_t syscall_number{}; + asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + + switch (syscall_number) { - case 0: + case 1: + // Write VGA + break; + case 60U: + // Exit break; default: break; -- cgit v1.2.3 From f0627d43909a8c19f41f3699757918c0185b5f1a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 30 Apr 2025 12:53:44 +0000 Subject: fix cs register after sysretq --- arch/x86_64/src/context_switching/main.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 2a2a188..8d1c019 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -42,7 +42,7 @@ namespace teachos::arch::context_switching : "memory"); asm volatile("syscall"); - video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } @@ -70,16 +70,12 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall - - // @MTO: This produces following values: - // After SYSCALL: CS = 0x10, SS = 0x18 - // After SYSRETQ: CS = 0x43, SS = 0x3b - // - // We probably need to modify our GDT, because the cs+8 = ss is an issue we cannot solve. - // Also, CS = 0x43 is weird. I expected it to be 0x33. + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall. + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR; + // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the + // cs register (See https://www.felixcloutier.com/x86/sysret). + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR - 0x10; uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); -- cgit v1.2.3 From 5eb8d63a6ece530cb1d56217a046553b4b96245d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 30 Apr 2025 14:50:34 +0000 Subject: Note linux calling contract for implementation --- arch/x86_64/src/context_switching/main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 8d1c019..7db9583 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -35,6 +35,16 @@ namespace teachos::arch::context_switching { video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + // RFLAGS is saved into R11, RIP of the next instruction into RCX + // Required for SYSRETURN to know where to return too. + // Additional state needs to be saved by calling convention: + + // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) + // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 + // Not used registers: RBX, RSP, R12, R13, R14 + + // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: + // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html uint64_t new_value = 60U; asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -70,7 +80,7 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall. + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the -- cgit v1.2.3 From 7c045d8ded72017ff11fd4b9b02148987b944caf Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 1 May 2025 12:25:40 +0000 Subject: WIP experiment with converting GDT to 8-Byte entries --- arch/x86_64/src/context_switching/main.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7db9583..5901998 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -29,7 +29,19 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + auto reload_gdtr() -> void + { + // asm volatile("pushq $0x8\n\t" // Push new CS + // "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX + // "pushq %%rax\n\t" // Push return address + // "lretq\n" // Far return (loads CS:RIP) + // "1:\n\t" // Label to return to + // : + // : + // : "rax", "memory"); + + kernel::cpu::call(KERNEL_CODE_POINTER); + } auto user_mode_main() -> void { @@ -83,9 +95,7 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the - // cs register (See https://www.felixcloutier.com/x86/sysret). - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR - 0x10; + uint64_t user_cs = KERNEL_CODE_SEGMENT_SELECTOR; uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); @@ -102,17 +112,17 @@ namespace teachos::arch::context_switching { kernel::cpu::clear_interrupt_flag(); - segment_descriptor_table::update_global_descriptor_table_register(); + segment_descriptor_table::update_gdtr(); interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - reload_global_descriptor_table_register(); + reload_gdtr(); segment_descriptor_table::update_task_state_segment_register(); kernel::cpu::set_interrupt_flag(); initalized = true; } - descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } -- cgit v1.2.3 From 099a7fbbc35a71f98553fa39899f2d17c555242f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 2 May 2025 14:49:06 +0000 Subject: Finish implementing 8-byte GDT entries and syscall arg loads. --- arch/x86_64/src/context_switching/main.cpp | 58 ++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5901998..7449d84 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -31,14 +31,14 @@ namespace teachos::arch::context_switching auto reload_gdtr() -> void { - // asm volatile("pushq $0x8\n\t" // Push new CS - // "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX - // "pushq %%rax\n\t" // Push return address - // "lretq\n" // Far return (loads CS:RIP) - // "1:\n\t" // Label to return to - // : - // : - // : "rax", "memory"); + /*asm volatile("pushq $0x8\n\t" // Push new CS + "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX + "pushq %%rax\n\t" // Push return address + "lretq\n" // Far return (loads CS:RIP) + "1:\n\t" // Label to return to + : + : + : "rax", "memory");*/ kernel::cpu::call(KERNEL_CODE_POINTER); } @@ -57,21 +57,33 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - uint64_t new_value = 60U; + uint64_t syscall_number = 60U; asm volatile("mov %[input], %%rax" : /* no output from call */ - : [input] "r"(new_value) + : [input] "r"(syscall_number) : "memory"); asm volatile("syscall"); - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); + // TODO: Reading RAX value does not work because the read itself changes the RAX value?! + // asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_value)); + + // TODO: Causes a general protection fault after the sysreturn? + // If removed instead it will cause a general protection fault after leaving this main method to return to kernel + // mode. But CS and SS are still configured for User mode. + /*video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black);*/ } auto syscall_handler() -> void { - uint64_t syscall_number{}; + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + asm volatile("mov %%rdi, %[output]" : [output] "=r"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=r"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=r"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=r"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=r"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=r"(arg_5)); switch (syscall_number) { @@ -85,7 +97,17 @@ namespace teachos::arch::context_switching break; } - asm volatile("sysretq"); + uint64_t result = 0U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "r"(result) + : "memory"); + + // Use SYSRET instead of SYSRETQ, because the latter would add 0x10 to bits [48:63] of IA32_STAR_ADDRESS for the + // Code Segment. But only add 0x8 to bits [48:63] of IA32_STAR_ADDRESS for the Stack Segment, which means either + // the Stack Segment or Code Segment is wrong. Whereas the former does not add 0x10 for the Code Segment and + // therefore fixes the aformentioned issue. + asm volatile("sysret"); } auto enable_systemcall() -> void @@ -94,9 +116,9 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t user_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const user_cs = USER_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); @@ -116,7 +138,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::update_interrupt_descriptor_table_register(); reload_gdtr(); - segment_descriptor_table::update_task_state_segment_register(); + segment_descriptor_table::update_tss_register(); kernel::cpu::set_interrupt_flag(); initalized = true; -- cgit v1.2.3 From 4b8674bee6089aef1e2c6b9064c6109f1cd392da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 3 May 2025 07:24:55 +0000 Subject: Remove zomby code and fix 32-bit compability crash --- arch/x86_64/src/context_switching/main.cpp | 38 +++++++----------------------- 1 file changed, 8 insertions(+), 30 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7449d84..06c0810 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -20,8 +20,6 @@ namespace teachos::arch::context_switching constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - constexpr interrupt_descriptor_table::segment_selector KERNEL_DATA_SEGMENT_SELECTOR{ - 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ @@ -29,19 +27,7 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - auto reload_gdtr() -> void - { - /*asm volatile("pushq $0x8\n\t" // Push new CS - "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX - "pushq %%rax\n\t" // Push return address - "lretq\n" // Far return (loads CS:RIP) - "1:\n\t" // Label to return to - : - : - : "rax", "memory");*/ - - kernel::cpu::call(KERNEL_CODE_POINTER); - } + auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } auto user_mode_main() -> void { @@ -64,14 +50,11 @@ namespace teachos::arch::context_switching : "memory"); asm volatile("syscall"); - // TODO: Reading RAX value does not work because the read itself changes the RAX value?! - // asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_value)); - - // TODO: Causes a general protection fault after the sysreturn? - // If removed instead it will cause a general protection fault after leaving this main method to return to kernel - // mode. But CS and SS are still configured for User mode. - /*video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black);*/ + // Reading RAX decrements value by one in 32-bit compatability mode it also crashes vga write, therfore use + // SYSRETQ instead of SYSRET so we do not return into 32-bit compatability mode. + asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); } auto syscall_handler() -> void @@ -103,11 +86,7 @@ namespace teachos::arch::context_switching : [input] "r"(result) : "memory"); - // Use SYSRET instead of SYSRETQ, because the latter would add 0x10 to bits [48:63] of IA32_STAR_ADDRESS for the - // Code Segment. But only add 0x8 to bits [48:63] of IA32_STAR_ADDRESS for the Stack Segment, which means either - // the Stack Segment or Code Segment is wrong. Whereas the former does not add 0x10 for the Code Segment and - // therefore fixes the aformentioned issue. - asm volatile("sysret"); + asm volatile("sysretq"); } auto enable_systemcall() -> void @@ -117,8 +96,7 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const user_cs = USER_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (user_cs << 48); + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); -- cgit v1.2.3 From 5a8c9d2f2e4a3d2810f81c35070c6ef0926cfdd1 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 3 May 2025 09:45:45 +0000 Subject: write wrapper function for syscall --- arch/x86_64/src/context_switching/main.cpp | 71 ++++-------------------------- 1 file changed, 8 insertions(+), 63 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 06c0810..7fe159e 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,11 +1,11 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/msr.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/video/vga/text.hpp" @@ -14,10 +14,6 @@ namespace teachos::arch::context_switching { namespace { - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, @@ -31,8 +27,6 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); - // RFLAGS is saved into R11, RIP of the next instruction into RCX // Required for SYSRETURN to know where to return too. // Additional state needs to be saved by calling convention: @@ -43,65 +37,16 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - uint64_t syscall_number = 60U; - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "r"(syscall_number) - : "memory"); - asm volatile("syscall"); - - // Reading RAX decrements value by one in 32-bit compatability mode it also crashes vga write, therfore use - // SYSRETQ instead of SYSRET so we do not return into 32-bit compatability mode. - asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } - auto syscall_handler() -> void - { - uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; - asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); - asm volatile("mov %%rdi, %[output]" : [output] "=r"(arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=r"(arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=r"(arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=r"(arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=r"(arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=r"(arg_5)); - - switch (syscall_number) + const char syscall_message[32] = "Successfully entered user mode!"; + auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); + + if (!error) { - case 1: - // Write VGA - break; - case 60U: - // Exit - break; - default: - break; + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); } - - uint64_t result = 0U; - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "r"(result) - : "memory"); - - asm volatile("sysretq"); } - - auto enable_systemcall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -129,7 +74,7 @@ namespace teachos::arch::context_switching auto switch_to_user_mode() -> void { - enable_systemcall(); + syscall::enable_syscall(); switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); } -- cgit v1.2.3 From 4d4e23116284f41329ea809e2bda86feea1b325c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 10:51:12 +0000 Subject: fix returning from syscall --- arch/x86_64/src/context_switching/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7fe159e..6c6ec1a 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -27,6 +27,7 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { + // TODO: Remove or replace this wall of text // RFLAGS is saved into R11, RIP of the next instruction into RCX // Required for SYSRETURN to know where to return too. // Additional state needs to be saved by calling convention: @@ -38,7 +39,7 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - const char syscall_message[32] = "Successfully entered user mode!"; + const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); if (!error) -- cgit v1.2.3 From ccb0fcb78c0d22ebaeb9aa37f1941b0d44c98038 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 11:07:48 +0000 Subject: move user-mode code into own namespace and linker section --- arch/x86_64/src/context_switching/main.cpp | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 6c6ec1a..a112924 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -8,6 +8,7 @@ #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" +#include "arch/user/main.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching @@ -24,30 +25,6 @@ namespace teachos::arch::context_switching 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } - - auto user_mode_main() -> void - { - // TODO: Remove or replace this wall of text - // RFLAGS is saved into R11, RIP of the next instruction into RCX - // Required for SYSRETURN to know where to return too. - // Additional state needs to be saved by calling convention: - - // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) - // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 - // Not used registers: RBX, RSP, R12, R13, R14 - - // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: - // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - - const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); - - if (!error) - { - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } - } } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -76,7 +53,7 @@ namespace teachos::arch::context_switching auto switch_to_user_mode() -> void { syscall::enable_syscall(); - switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); } auto switch_context(interrupt_descriptor_table::segment_selector data_segment, -- cgit v1.2.3 From c1dff44858ebdb3cd5a49e84179796e44e7eb91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 06:41:31 +0000 Subject: Fix recursive include using extra file --- arch/x86_64/src/context_switching/main.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/x86_64/src/context_switching/main.cpp') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index a112924..9539428 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,15 +1,12 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" +#include "arch/context_switching/syscall/syscall_enable.hpp" #include "arch/kernel/cpu/call.hpp" -#include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/user/main.hpp" -#include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching { -- cgit v1.2.3