proc/WIP: better handling for TLS

This commit is contained in:
2024-11-17 23:32:07 +02:00
parent 17eca4c0c0
commit e0e39d2f23
52 changed files with 1766 additions and 753 deletions
+18 -78
View File
@@ -3,53 +3,21 @@
.set MSR_IA32_FS_BASE, 0xC0000100
.macro SAVE_TASK_STATE
sub ${context_size}, %rsp
mov %rbx, 0(%rsp)
mov %r12, 8(%rsp)
mov %r13, 16(%rsp)
mov %r14, 24(%rsp)
mov %r15, 32(%rsp)
// Store FS_BASE
mov $MSR_IA32_FS_BASE, %ecx
rdmsr
mov %edx, %ecx
shl $32, %rcx
or %rax, %rcx
mov %rcx, 40(%rsp)
// TODO save %fs
mov %rbp, 48(%rsp)
mov %cr3, %rbx
mov %rbx, 56(%rsp)
push %rbp
push %r15
push %r14
push %r13
push %r12
push %rbx
.endm
.macro LOAD_TASK_STATE
mov 56(%rsp), %rbx
mov %rbx, %cr3
mov 0(%rsp), %rbx
mov 8(%rsp), %r12
mov 16(%rsp), %r13
mov 24(%rsp), %r14
mov 32(%rsp), %r15
// Load FS_BASE
// edx:eax = fs_base
mov 40(%rsp), %rdx
mov %edx, %eax
shr $32, %rdx
mov $MSR_IA32_FS_BASE, %ecx
wrmsr
// mov 40(%rsp), %fs
mov 48(%rsp), %rbp
add ${context_size}, %rsp
pop %rbx
pop %r12
pop %r13
pop %r14
pop %r15
pop %rbp
.endm
.global __x86_64_task_enter_user
@@ -134,55 +102,27 @@ __x86_64_task_enter_kernel:
// %rsi - from struct ptr, %rdi - to struct ptr
__x86_64_switch_task:
// save state to source stack
SAVE_TASK_STATE
mov %rsp, 0(%rsi)
// TSS.RSP0
mov 8(%rdi), %rax
// Kernel stack
mov 0(%rdi), %rdi
mov %rdi, %rsp
// Load TSS.RSP0
mov %gs:(8), %rdi
mov %rax, 4(%rdi)
// load destination stack
mov 0(%rdi), %rsp
LOAD_TASK_STATE
ret
__x86_64_switch_and_drop:
// TSS.RSP0
mov 8(%rdi), %rax
// Kernel stack
mov 0(%rdi), %rdi
mov %rdi, %rsp
// Load TSS.RSP0
mov %gs:(8), %rdi
mov %rax, 4(%rdi)
mov 0(%rdi), %rsp
// Call thread drop before loading the state
mov %rsi, %rdi
call __arch_drop_thread
LOAD_TASK_STATE
ret
// %rdi - to struct ptr
__x86_64_enter_task:
// TSS.RSP0
mov 8(%rdi), %rax
// Kernel stack
mov 0(%rdi), %rdi
mov %rdi, %rsp
// Load TSS.RSP0
mov %gs:(8), %rdi
mov %rax, 4(%rdi)
mov 0(%rdi), %rsp
LOAD_TASK_STATE
ret
+94 -83
View File
@@ -4,11 +4,12 @@ use kernel_arch_interface::{
mem::{KernelTableManager, PhysicalMemoryAllocator},
task::{ForkFrame, StackBuilder, TaskContext, TaskFrame, UserContextInfo},
};
use kernel_arch_x86::registers::FpuContext;
use kernel_arch_x86::registers::{FpuContext, CR3, MSR_IA32_FS_BASE};
use libk_mm_interface::address::{AsPhysicalAddress, PhysicalAddress};
use tock_registers::interfaces::Writeable;
use yggdrasil_abi::{arch::SavedFrame, error::Error};
use crate::mem::KERNEL_TABLES;
use crate::{mem::KERNEL_TABLES, ArchitectureImpl};
/// Frame saved onto the stack when taking an IRQ
#[derive(Debug)]
@@ -93,8 +94,8 @@ pub struct SyscallFrame {
struct Inner {
// 0x00
sp: usize,
// 0x08
tss_rsp0: usize,
fs_base: usize,
}
/// x86-64 implementation of a task context
@@ -107,14 +108,14 @@ pub struct TaskContextImpl<
fpu_context: UnsafeCell<FpuContext>,
stack_base_phys: PhysicalAddress,
stack_size: usize,
tss_rsp0: usize,
cr3: usize,
_alloc: PhantomData<PA>,
_table_manager: PhantomData<K>,
}
// 8 registers + return address (which is not included)
const COMMON_CONTEXT_SIZE: usize = 8 * 8;
impl TaskFrame for IrqFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
@@ -348,52 +349,71 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
TaskContextImpl<K, PA>
{
/// Constructs a new task context from a "forked" syscall frame
pub(super) unsafe fn from_syscall_frame(frame: &SyscallFrame, cr3: u64) -> Result<Self, Error> {
const USER_TASK_PAGES: usize = 8;
pub(super) unsafe fn from_syscall_frame(
_frame: &SyscallFrame,
_cr3: u64,
) -> Result<Self, Error> {
todo!()
// const USER_TASK_PAGES: usize = 8;
let stack_base_phys = PA::allocate_contiguous_pages(USER_TASK_PAGES)?;
let stack_base = stack_base_phys.raw_virtualize::<K>();
// let stack_base_phys = PA::allocate_contiguous_pages(USER_TASK_PAGES)?;
// let stack_base = stack_base_phys.raw_virtualize::<K>();
let mut stack = StackBuilder::new(stack_base, USER_TASK_PAGES * 0x1000);
// let mut stack = StackBuilder::new(stack_base, USER_TASK_PAGES * 0x1000);
// iretq frame
stack.push(0x1B);
stack.push(frame.user_sp as _);
stack.push(0x200);
stack.push(0x23);
stack.push(frame.user_ip as _);
// // iretq frame
// stack.push(0x1B);
// stack.push(frame.user_sp as _);
// stack.push(0x200);
// stack.push(0x23);
// stack.push(frame.user_ip as _);
stack.push(frame.args[5] as _); // r9
stack.push(frame.args[4] as _); // r8
stack.push(frame.args[3] as _); // r10
stack.push(frame.args[2] as _); // rdx
stack.push(frame.args[1] as _); // rsi
stack.push(frame.args[0] as _); // rdi
// stack.push(frame.args[5] as _); // r9
// stack.push(frame.args[4] as _); // r8
// stack.push(frame.args[3] as _); // r10
// stack.push(frame.args[2] as _); // rdx
// stack.push(frame.args[1] as _); // rsi
// stack.push(frame.args[0] as _); // rdi
// callee-saved registers
stack.push(__x86_64_task_enter_from_fork as _);
// // callee-saved registers
// stack.push(__x86_64_task_enter_from_fork as _);
stack.push(cr3 as _);
// stack.push(cr3 as _);
stack.push(frame.rbp as _);
stack.push(0x12345678); // XXX TODO: fs_base from SyscallFrame
stack.push(frame.r15 as _);
stack.push(frame.r14 as _);
stack.push(frame.r13 as _);
stack.push(frame.r12 as _);
stack.push(frame.rbx as _);
// stack.push(frame.rbp as _);
// stack.push(0x12345678); // XXX TODO: fs_base from SyscallFrame
// stack.push(frame.r15 as _);
// stack.push(frame.r14 as _);
// stack.push(frame.r13 as _);
// stack.push(frame.r12 as _);
// stack.push(frame.rbx as _);
let sp = stack.build();
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
// let sp = stack.build();
// let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
Ok(Self {
inner: UnsafeCell::new(Inner { sp, tss_rsp0: rsp0 }),
fpu_context: UnsafeCell::new(FpuContext::new(true)),
stack_base_phys,
stack_size: USER_TASK_PAGES * 0x1000,
_alloc: PhantomData,
_table_manager: PhantomData,
})
// Ok(Self {
// inner: UnsafeCell::new(Inner { sp, tss_rsp0: rsp0 }),
// fpu_context: UnsafeCell::new(FpuContext::new(true)),
// stack_base_phys,
// stack_size: USER_TASK_PAGES * 0x1000,
// _alloc: PhantomData,
// _table_manager: PhantomData,
// })
}
unsafe fn store_state(&self) {
FpuContext::store(self.fpu_context.get());
// No need to save TSS/%cr3/%fs base back into the TCB, only the kernel
// can make changes to those
}
unsafe fn load_state(&self) {
FpuContext::restore(self.fpu_context.get());
// When the task is interrupted from Ring 3, make the CPU load
// the top of its kernel stack
ArchitectureImpl::set_local_tss_sp0(self.tss_rsp0);
MSR_IA32_FS_BASE.set((*self.inner.get()).fs_base as u64);
CR3.set_address(self.cr3);
}
}
@@ -411,6 +431,8 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
fn kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<Self, Error> {
const KERNEL_TASK_PAGES: usize = 32;
let cr3: usize = unsafe { KERNEL_TABLES.lock().as_physical_address() }.into();
let stack_base_phys = PA::allocate_contiguous_pages(KERNEL_TASK_PAGES)?;
let stack_base = stack_base_phys.raw_virtualize::<K>();
@@ -420,23 +442,21 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(entry as _);
stack.push(arg);
setup_common_context(
&mut stack,
__x86_64_task_enter_kernel as _,
unsafe { KERNEL_TABLES.lock().as_physical_address() }.into(),
0,
);
setup_common_context(&mut stack, __x86_64_task_enter_kernel as _);
let sp = stack.build();
// TODO stack is leaked
Ok(Self {
inner: UnsafeCell::new(Inner { sp, tss_rsp0: 0 }),
inner: UnsafeCell::new(Inner { sp, fs_base: 0 }),
fpu_context: UnsafeCell::new(FpuContext::new(false)),
stack_base_phys,
stack_size: KERNEL_TASK_PAGES * 0x1000,
tss_rsp0: 0,
cr3,
_alloc: PhantomData,
_table_manager: PhantomData,
})
@@ -460,53 +480,51 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(context.argument);
stack.push(context.stack_pointer);
setup_common_context(
&mut stack,
__x86_64_task_enter_user as _,
context.address_space,
context.tls,
);
setup_common_context(&mut stack, __x86_64_task_enter_user as _);
let sp = stack.build();
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
Ok(Self {
inner: UnsafeCell::new(Inner { sp, tss_rsp0: rsp0 }),
inner: UnsafeCell::new(Inner {
sp,
fs_base: context.thread_pointer,
}),
fpu_context: UnsafeCell::new(FpuContext::new(true)),
stack_base_phys,
stack_size: USER_TASK_PAGES * 0x1000,
tss_rsp0: rsp0,
cr3: context.address_space as usize,
_alloc: PhantomData,
_table_manager: PhantomData,
})
}
unsafe fn enter(&self) -> ! {
FpuContext::restore(self.fpu_context.get());
self.load_state();
__x86_64_enter_task(self.inner.get())
}
unsafe fn switch(&self, from: &Self) {
let dst = self.inner.get();
let src = from.inner.get();
if dst != src {
// Save the old context
FpuContext::store(from.fpu_context.get());
// Load next context
FpuContext::restore(self.fpu_context.get());
__x86_64_switch_task(dst, src);
if core::ptr::addr_eq(self, from) {
return;
}
from.store_state();
self.load_state();
__x86_64_switch_task(self.inner.get(), from.inner.get())
}
unsafe fn switch_and_drop(&self, thread: *const ()) {
let dst = self.inner.get();
self.load_state();
__x86_64_switch_and_drop(self.inner.get(), thread)
}
FpuContext::restore(self.fpu_context.get());
__x86_64_switch_and_drop(dst, thread)
fn set_thread_pointer(&self, tp: usize) {
unsafe { (*self.inner.get()).fs_base = tp };
MSR_IA32_FS_BASE.set(tp as _);
}
}
@@ -524,13 +542,10 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
}
}
fn setup_common_context(builder: &mut StackBuilder, entry: usize, cr3: u64, fs_base: usize) {
fn setup_common_context(builder: &mut StackBuilder, entry: usize) {
builder.push(entry);
builder.push(cr3 as _);
builder.push(0); // %rbp
builder.push(fs_base); // %fs_base
builder.push(0); // %r15
builder.push(0); // %r14
builder.push(0); // %r13
@@ -547,8 +562,4 @@ extern "C" {
fn __x86_64_switch_and_drop(to: *mut Inner, from: *const ());
}
global_asm!(
include_str!("context.S"),
context_size = const COMMON_CONTEXT_SIZE,
options(att_syntax)
);
global_asm!(include_str!("context.S"), options(att_syntax));
+8
View File
@@ -84,6 +84,14 @@ impl ArchitectureImpl {
fn local_cpu_data() -> Option<&'static mut PerCpuData> {
unsafe { (Self::local_cpu() as *mut PerCpuData).as_mut() }
}
fn set_local_tss_sp0(sp: usize) {
let local_cpu = Self::local_cpu_data().unwrap();
unsafe {
(core::ptr::with_exposed_provenance_mut::<usize>(local_cpu.tss_address + 4))
.write_unaligned(sp);
}
}
}
impl Architecture for ArchitectureImpl {