Proper FPU init, fxsave/fxrstor for threads

This commit is contained in:
Mark
2020-02-07 15:02:06 +02:00
parent 31a4b8412a
commit 4878a0b06e
5 changed files with 62 additions and 0 deletions
+3
View File
@@ -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
+16
View File
@@ -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
+2
View File
@@ -16,5 +16,7 @@ struct thread_data {
uintptr_t rsp0_base, rsp0_size;
uintptr_t rsp3_base, rsp3_size;
void *fxsave;
};
#endif
+1
View File
@@ -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
View File
@@ -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);