sched: implement user-configurable fs and gs segment base addresses
This commit is contained in:
@@ -28,4 +28,6 @@
|
||||
static void __used common(void)
|
||||
{
|
||||
OFFSET(THREAD_sp, struct thread, tr_sp);
|
||||
OFFSET(THREAD_fsbase, struct thread, tr_ml.tr_fsbase);
|
||||
OFFSET(THREAD_gsbase, struct thread, tr_ml.tr_gsbase);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MSR_FS_BASE 0xC0000100
|
||||
#define MSR_GS_BASE 0xC0000101
|
||||
#define MSR_KERNEL_GS_BASE 0xC0000102
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#include <kernel/sched.h>
|
||||
|
||||
struct ml_thread {
|
||||
virt_addr_t tr_gsbase, tr_fsbase;
|
||||
};
|
||||
|
||||
struct ml_cpu_context;
|
||||
|
||||
/* switch from one thread to another. the stack of the `to` thread must have
|
||||
@@ -28,4 +32,15 @@ extern kern_status_t ml_thread_prepare_user_context(
|
||||
const uintptr_t *args,
|
||||
size_t nr_args);
|
||||
|
||||
extern kern_status_t ml_thread_config_get(
|
||||
struct thread *thread,
|
||||
kern_config_key_t key,
|
||||
void *out,
|
||||
size_t max);
|
||||
extern kern_status_t ml_thread_config_set(
|
||||
struct thread *thread,
|
||||
kern_config_key_t key,
|
||||
const void *ptr,
|
||||
size_t len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <arch/msr.h>
|
||||
#include <kernel/machine/cpu.h>
|
||||
#include <kernel/machine/thread.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
#define MAX_REG_ARGS 6
|
||||
#define REG_ARG_0 rdi
|
||||
@@ -77,3 +79,52 @@ extern kern_status_t ml_thread_prepare_user_context(
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t ml_thread_config_get(
|
||||
struct thread *thread,
|
||||
kern_config_key_t key,
|
||||
void *out,
|
||||
size_t max)
|
||||
{
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t ml_thread_config_set(
|
||||
struct thread *thread,
|
||||
kern_config_key_t key,
|
||||
const void *ptr,
|
||||
size_t len)
|
||||
{
|
||||
switch (key) {
|
||||
case THREAD_CFG_FSBASE:
|
||||
if (len != sizeof(thread->tr_ml.tr_fsbase)) {
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
thread->tr_ml.tr_fsbase = *(virt_addr_t *)ptr;
|
||||
if (thread == current_thread()) {
|
||||
wrmsr(MSR_FS_BASE, thread->tr_ml.tr_fsbase);
|
||||
}
|
||||
|
||||
break;
|
||||
case THREAD_CFG_GSBASE:
|
||||
if (len != sizeof(thread->tr_ml.tr_gsbase)) {
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
thread->tr_ml.tr_gsbase = *(virt_addr_t *)ptr;
|
||||
if (thread == current_thread()) {
|
||||
/* we're in the kernel right now, so the user and kernel
|
||||
* gs-base registers are swapped. when we return to
|
||||
* usermode, this value will be swapped back into
|
||||
* the user gs-base register */
|
||||
wrmsr(MSR_KERNEL_GS_BASE, thread->tr_ml.tr_gsbase);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,22 @@ ml_thread_switch:
|
||||
push %rax
|
||||
push %rcx
|
||||
push %rdx
|
||||
|
||||
// set fs-base
|
||||
mov $0xC0000100, %rcx
|
||||
movq THREAD_fsbase(%rsi), %rax
|
||||
movq THREAD_fsbase(%rsi), %rdx
|
||||
shr $32, %rdx
|
||||
wrmsr
|
||||
|
||||
// set (kernel) gs-base (it will be swapped back into user-gs-base at
|
||||
// the end of this function)
|
||||
mov $0xC0000102, %rcx
|
||||
movq THREAD_gsbase(%rsi), %rax
|
||||
movq THREAD_gsbase(%rsi), %rdx
|
||||
shr $32, %rdx
|
||||
wrmsr
|
||||
|
||||
push %rbx
|
||||
pushq $0
|
||||
push %rbp
|
||||
|
||||
Reference in New Issue
Block a user