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/syscall/main.cpp | 57 ++++++++++++++++++ .../context_switching/syscall/syscall_handler.cpp | 68 ++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 arch/x86_64/src/context_switching/syscall/main.cpp create mode 100644 arch/x86_64/src/context_switching/syscall/syscall_handler.cpp (limited to 'arch/x86_64/src/context_switching/syscall') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp new file mode 100644 index 0000000..e90f503 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -0,0 +1,57 @@ +#include "arch/context_switching/syscall/main.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" +#include "arch/kernel/cpu/msr.hpp" + +#include + +namespace teachos::arch::context_switching::syscall +{ + namespace + { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + + } // namespace + + auto enable_syscall() -> 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); + } + + auto syscall(type syscall_number, arguments args) -> uint64_t + { + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(syscall_number) + : "memory"); + + asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); + asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); + asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); + asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); + asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); + asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); + + asm volatile("syscall"); + + uint64_t result{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(result)); + return result; + } + +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp new file mode 100644 index 0000000..f6e1c9e --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -0,0 +1,68 @@ +#include "arch/context_switching/syscall/syscall_handler.hpp" + +#include "arch/exception_handling/panic.hpp" +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::context_switching::syscall +{ + + namespace + { + auto write_to_vga_buffer(uint64_t buffer) + { + video::vga::text::write(reinterpret_cast(buffer), + video::vga::text::common_attributes::green_on_black); + } + } // namespace + + auto syscall_handler() -> void + { + // Saving state of rcx and r11 because it is required by sysretq to function. + // Calls to other functions potentially overwrite these registers, because of + // callee saved calling convention. + uint64_t return_instruction_pointer, rflags = {}; + asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); + asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); + + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); + + // RAX is read last, because paired with our type enum, we can use it to check + // if the register has been written by the compiled code between executing the syscall + // and now. + asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); + + switch (static_cast(syscall_number)) + { + case WRITE: + write_to_vga_buffer(arg_0); + break; + default: + teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); + break; + } + + uint64_t result = 0U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(result) + : "memory"); + + asm volatile("mov %[input], %%rcx" + : /* no output from call */ + : [input] "m"(return_instruction_pointer) + : "memory"); + asm volatile("mov %[input], %%r11" + : /* no output from call */ + : [input] "m"(rflags) + : "memory"); + + asm volatile("sysretq"); + } + +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file -- cgit v1.2.3