Proper FPU init, fxsave/fxrstor for threads
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "arch/amd64/hw/ps2.h"
|
||||
#include "arch/amd64/cpuid.h"
|
||||
#include "arch/amd64/mm/mm.h"
|
||||
#include "arch/amd64/fpu.h"
|
||||
#include "sys/block/ram.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/kernel.h"
|
||||
@@ -77,6 +78,8 @@ void kernel_early_init(struct amd64_loader_data *data) {
|
||||
|
||||
amd64_make_random_seed();
|
||||
|
||||
amd64_fpu_init();
|
||||
|
||||
#if defined(AMD64_SMP)
|
||||
amd64_smp_init();
|
||||
#endif
|
||||
|
||||
@@ -62,6 +62,14 @@ context_exec_enter:
|
||||
context_switch_to:
|
||||
// %rdi - new thread
|
||||
// %rsi - from
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
|
||||
call context_save_fpu
|
||||
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
|
||||
pushq %r15
|
||||
pushq %r14
|
||||
pushq %r13
|
||||
@@ -83,6 +91,14 @@ context_switch_first:
|
||||
popq %r14
|
||||
popq %r15
|
||||
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
|
||||
call context_restore_fpu
|
||||
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
|
||||
// Load TSS.RSP0 for user -> kernel transition
|
||||
// %rax = top of task's stack
|
||||
movq THREAD_RSP0_TOP(%rdi), %rax
|
||||
|
||||
@@ -16,5 +16,7 @@ struct thread_data {
|
||||
|
||||
uintptr_t rsp0_base, rsp0_size;
|
||||
uintptr_t rsp3_base, rsp3_size;
|
||||
|
||||
void *fxsave;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,7 @@ enum thread_state {
|
||||
|
||||
#define THREAD_KERNEL (1 << 0)
|
||||
#define THREAD_EMPTY (1 << 1)
|
||||
#define THREAD_FPU_SAVED (1 << 2)
|
||||
|
||||
#define thread_signal_clear(thr, signum) \
|
||||
(thr)->sigq &= ~(1ULL << ((signum) - 1))
|
||||
|
||||
@@ -40,6 +40,26 @@ struct sys_fork_frame {
|
||||
LIST_HEAD(threads_all_head);
|
||||
static pid_t last_kernel_pid = 0;
|
||||
static pid_t last_user_pid = 0;
|
||||
static uint64_t fxsave_buf[FXSAVE_REGION / 8] __attribute__((aligned(16)));
|
||||
|
||||
void context_save_fpu(struct thread *new, struct thread *old) {
|
||||
_assert(old);
|
||||
if (old->data.fxsave) {
|
||||
asm volatile ("fxsave (%0)"::"r"(fxsave_buf):"memory");
|
||||
memcpy(old->data.fxsave, fxsave_buf, FXSAVE_REGION);
|
||||
old->flags |= THREAD_FPU_SAVED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void context_restore_fpu(struct thread *new, struct thread *old) {
|
||||
_assert(new);
|
||||
if (new->flags & THREAD_FPU_SAVED) {
|
||||
memcpy(fxsave_buf, new->data.fxsave, FXSAVE_REGION);
|
||||
asm volatile ("fxrstor (%0)"::"r"(fxsave_buf):"memory");
|
||||
new->flags &= ~THREAD_FPU_SAVED;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t thread_alloc_pid(int is_user) {
|
||||
if (is_user) {
|
||||
@@ -226,6 +246,13 @@ int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) {
|
||||
thr->name[0] = 0;
|
||||
thr->flags = user ? 0 : THREAD_KERNEL;
|
||||
|
||||
if (!(thr->flags & THREAD_KERNEL)) {
|
||||
thr->data.fxsave = kmalloc(FXSAVE_REGION);
|
||||
_assert(thr->data.fxsave);
|
||||
} else {
|
||||
thr->data.fxsave = NULL;
|
||||
}
|
||||
|
||||
list_link_init(&thr->g_link);
|
||||
|
||||
uint64_t *stack = (uint64_t *) (thr->data.rsp0_base + thr->data.rsp0_size);
|
||||
@@ -375,6 +402,16 @@ int sys_fork(struct sys_fork_frame *frame) {
|
||||
|
||||
dst->signal_entry = src->signal_entry;
|
||||
|
||||
strcpy(dst->name, src->name);
|
||||
|
||||
dst->data.fxsave = kmalloc(FXSAVE_REGION);
|
||||
_assert(dst->data.fxsave);
|
||||
_assert(src->data.fxsave);
|
||||
|
||||
if (src->flags & THREAD_FPU_SAVED) {
|
||||
memcpy(dst->data.fxsave, src->data.fxsave, FXSAVE_REGION);
|
||||
}
|
||||
|
||||
thread_ioctx_fork(dst, src);
|
||||
|
||||
dst->state = THREAD_READY;
|
||||
@@ -546,6 +583,9 @@ int sys_execve(const char *path, const char **argv, const char **envp) {
|
||||
thr->data.cr3 = MM_PHYS(thr->space);
|
||||
thr->flags = 0;
|
||||
|
||||
thr->data.fxsave = kmalloc(FXSAVE_REGION);
|
||||
_assert(thr->data.fxsave);
|
||||
|
||||
mm_space_clone(thr->space, mm_kernel, MM_CLONE_FLG_KERNEL);
|
||||
} else {
|
||||
mm_space_release(thr->space);
|
||||
|
||||
Reference in New Issue
Block a user