From 19f9812648303e32cf5586fc82747607cfda2cbb Mon Sep 17 00:00:00 2001 From: Fabian Ruhland Date: Tue, 11 Jun 2024 15:41:04 +0200 Subject: [PATCH] kernel: Use 'swapgs' to access rsp0 entry in tss --- os/kernel/src/lib.rs | 20 +++--- os/kernel/src/process/thread.rs | 16 ++--- os/kernel/src/syscall/syscall_dispatcher.rs | 68 +++++++++++++-------- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/os/kernel/src/lib.rs b/os/kernel/src/lib.rs index 7fae94b..b05a2a3 100644 --- a/os/kernel/src/lib.rs +++ b/os/kernel/src/lib.rs @@ -46,10 +46,11 @@ use x86_64::structures::idt::InterruptDescriptorTable; use x86_64::structures::paging::frame::PhysFrameRange; use x86_64::structures::paging::PhysFrame; use x86_64::structures::tss::TaskStateSegment; -use x86_64::{PhysAddr, VirtAddr}; +use x86_64::PhysAddr; use crate::device::pci::PciBus; use crate::memory::PAGE_SIZE; use crate::process::process::ProcessManager; +use crate::syscall::syscall_dispatcher::CoreLocalStorage; extern crate alloc; @@ -103,6 +104,7 @@ impl EfiSystemTable { static GDT: Mutex = Mutex::new(GlobalDescriptorTable::new()); static TSS: Mutex = Mutex::new(TaskStateSegment::new()); static IDT: Mutex = Mutex::new(InterruptDescriptorTable::new()); +static CORE_LOCAL_STORAGE: Mutex = Mutex::new(CoreLocalStorage::new()); static EFI_SYSTEM_TABLE: Once = Once::new(); static ACPI_TABLES: Once>> = Once::new(); static INIT_RAMDISK: Once = Once::new(); @@ -223,6 +225,10 @@ pub fn idt() -> &'static Mutex { &IDT } +pub fn core_local_storage() -> &'static Mutex { + &CORE_LOCAL_STORAGE +} + pub fn acpi_tables() -> &'static Mutex> { ACPI_TABLES.get().expect("Trying to access ACPI tables before initialization!") } @@ -286,14 +292,4 @@ pub fn ps2_devices() -> &'static PS2 { pub fn pci_bus() -> &'static PciBus { PCI.get().expect("Trying to access PCI bus before initialization!") -} - -#[no_mangle] -pub extern "C" fn tss_set_rsp0(rsp0: u64) { - tss().lock().privilege_stack_table[0] = VirtAddr::new(rsp0); -} - -#[no_mangle] -pub extern "C" fn tss_get_rsp0() -> u64 { - tss().lock().privilege_stack_table[0].as_u64() -} +} \ No newline at end of file diff --git a/os/kernel/src/process/thread.rs b/os/kernel/src/process/thread.rs index e970aa8..56dd557 100644 --- a/os/kernel/src/process/thread.rs +++ b/os/kernel/src/process/thread.rs @@ -17,6 +17,7 @@ use crate::{memory, process_manager, scheduler, tss}; use crate::memory::alloc::StackAllocator; use crate::memory::r#virtual::{VirtualMemoryArea, VmaType}; use crate::process::process::Process; +use crate::syscall::syscall_dispatcher::CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX; pub const MAIN_USER_STACK_START: usize = 0x400000000000; pub const MAX_USER_STACK_SIZE: usize = 0x40000000; @@ -344,17 +345,11 @@ unsafe extern "C" fn thread_switch(current_rsp0: *mut u64, next_rsp0: u64, next_ // Save stack pointer in 'current_rsp0' (first parameter) "mov [rdi], rsp", - // Store rsi and rcx in r12 and r13, as they might be overwritten by the following function call - "mov r12, rsi", - "mov r13, rcx", - // Set rsp0 of kernel stack in tss (third parameter 'next_rsp0_end') - "mov rdi, rdx", - "call tss_set_rsp0", - - // Restore rsi and rcx - "mov rcx, r13", - "mov rsi, r12", + "swapgs", // Setup core local storage access via gs base + "mov rax,gs:[{CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX}]", // Load pointer to rsp0 entry of tss into rax + "mov [rax],rdx", // Set rsp0 entry in tss to 'next_rsp0_end' (third parameter) + "swapgs", // Restore gs base // Switch address space (fourth parameter 'next_cr3') "mov cr3, rcx", @@ -380,6 +375,7 @@ unsafe extern "C" fn thread_switch(current_rsp0: *mut u64, next_rsp0: u64, next_ "call unlock_scheduler", "ret", // Return to next thread + CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX = const CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX, options(noreturn) ) } \ No newline at end of file diff --git a/os/kernel/src/syscall/syscall_dispatcher.rs b/os/kernel/src/syscall/syscall_dispatcher.rs index 49e5aa2..2f6283c 100644 --- a/os/kernel/src/syscall/syscall_dispatcher.rs +++ b/os/kernel/src/syscall/syscall_dispatcher.rs @@ -1,11 +1,30 @@ use core::arch::asm; +use core::mem::size_of; +use core::ops::Deref; +use core::ptr; use x86_64::registers::control::{Efer, EferFlags}; -use x86_64::registers::model_specific::{LStar, Star}; +use x86_64::registers::model_specific::{KernelGsBase, LStar, Star}; use x86_64::structures::gdt::SegmentSelector; use x86_64::{PrivilegeLevel, VirtAddr}; use syscall::NUM_SYSCALLS; +use crate::{core_local_storage, tss}; use crate::syscall::{sys_write, sys_thread_exit, sys_thread_sleep, sys_thread_switch, sys_process_id, sys_thread_id, sys_read, sys_map_user_heap, sys_thread_join, sys_process_execute_binary, sys_get_system_time, sys_get_date, sys_set_date, sys_thread_create, sys_process_exit}; +pub const CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX: u64 = 0x00; +pub const CORE_LOCAL_STORAGE_USER_RSP_INDEX: u64 = 0x08; + + +#[repr(C, packed)] +pub struct CoreLocalStorage { + tss_rsp0_ptr: VirtAddr, + user_rsp: VirtAddr, +} + +impl CoreLocalStorage { + pub const fn new() -> Self { + Self { tss_rsp0_ptr: VirtAddr::zero(), user_rsp: VirtAddr::zero() } + } +} pub fn init() { // Enable system call extensions @@ -26,6 +45,11 @@ pub fn init() { // Set rip for syscall LStar::write(VirtAddr::new(syscall_handler as u64)); + + // Initialize core local storage (accessible via 'swapgs') + let mut core_local_storage = core_local_storage().lock(); + core_local_storage.tss_rsp0_ptr = VirtAddr::new(ptr::from_ref(tss().lock().deref()) as u64 + size_of::() as u64); + KernelGsBase::write(VirtAddr::new(ptr::from_ref(core_local_storage.deref()) as u64)); } #[no_mangle] @@ -75,7 +99,15 @@ unsafe extern "C" fn syscall_handler() { // Disable interrupts until we have switched to kernel stack "cli", - // Save registers (except rax, which is used for system call ID and return value) + // Switch to kernel stack + "swapgs", // Setup core local storage access via gs base + "mov gs:[{CORE_LOCAL_STORAGE_USER_RSP_INDEX}], rsp", // Temporarily store user rip in core local storage + "mov rsp, gs:[{CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX}]", // Load pointer to rsp0 entry of tss from core local storage + "mov rsp, [rsp]", // Dereference rsp0 pointer to switch to kernel stack + "push gs:[{CORE_LOCAL_STORAGE_USER_RSP_INDEX}]", // Store user rip on kernel stack (core local storage might be overwritten, when a thread switch occurs during system call execution) + "swapgs", // Restore gs base + + // Store registers (except rax, which is used for system call ID and return value) "push rbx", "push rcx", // Contains rip for returning to ring 3 "push rdx", @@ -90,34 +122,16 @@ unsafe extern "C" fn syscall_handler() { "push r14", "push r15", - // Switch to kernel stack and enable interrupts - "mov r15, rax", // Save system call ID in r15 - "mov r14, rdi", // Save first parameter in r14 - "mov r13, rsi", // Save second parameter in r13 - "mov r12, rdx", // Save third parameter in r12 - "call tss_get_rsp0", // Get kernel rsp (returned in rax) - "mov rbx, rax", // Save kernel rsp in rbx - "mov rcx, rsp", // Save user rsp in rcx - "mov rdx, r12", // Restore third parameter - "mov rsi, r13", // Restore second parameter - "mov rdi, r14", // Restore first parameter - "mov rax, r15", // Restore system call ID - "mov rsp, rbx", // Switch to kernel stack - "push rcx", // Save user rsp on stack + // Enable interrupts (we are now on the kernel stack and can handle them properly) "sti", // Check if system call ID is in bounds - "cmp rax, {}", + "cmp rax, {NUM_SYSCALLS}", "jge syscall_abort", // Panics and does not return // Call system call handler, corresponding to ID (in rax) "call syscall_disp", - // Switch to user stack (user rsp is last value on stack) - // Disable interrupts, since we are still in Ring 0 and no interrupt handler should be called with the user stack - "cli", - "pop rsp", - // Restore registers "pop r15", "pop r14", @@ -133,10 +147,16 @@ unsafe extern "C" fn syscall_handler() { "pop rcx", // Contains rip for returning to ring 3 "pop rbx", + // Switch back to user stack + "cli", // Disable interrupts, since we are still in Ring 0 and no interrupt handler should be called with the user stack + "pop rsp", // Restore rsp from kernel stack, + // Return to Ring 3 - // Interrupts will be enabled automatically, because eflags gets restored from r11 + // Interrupts will be enabled automatically, because eflags is restored from r11 "sysretq", - const NUM_SYSCALLS, + NUM_SYSCALLS = const NUM_SYSCALLS, + CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX = const CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX, + CORE_LOCAL_STORAGE_USER_RSP_INDEX = const CORE_LOCAL_STORAGE_USER_RSP_INDEX, options(noreturn) ); }