proc/WIP: better handling for TLS
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user