From 684b081a1600769ba0afd4224a6dcee5b9b61880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Fri, 30 Jan 2015 13:37:00 -0200 Subject: [PATCH] x86: fix FPU lazy swap The ucontext->x86_fxsave is initialize as 512 bytes of zeros, but it is not a valid value to be set onto FPU registers, causing a General Protection Fault: Interrupt 0x0d (General Protection Fault) while handling 0x07 (Device not available) EAX=0012f4c0 ECX=001336e4 EDX=001334ac EBX=001336e0 ESP=00123784 EBP=001237c8 ESI=00000200 EDI=00000000 Error code=00000000 CR0=80010031 CR2=00000000 CR3=0012d000 CR4=000001e0 EIP=0000:80010031 EFLAGS=0012d000 00000000 ??? Halting. So lets copy the initial state of FPU registers before FPU is used and set it as the initial state of FPU to new threads(coroutine). --- cpu/x86/x86_threading.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpu/x86/x86_threading.c b/cpu/x86/x86_threading.c index 0e58605508..da4c07a136 100644 --- a/cpu/x86/x86_threading.c +++ b/cpu/x86/x86_threading.c @@ -55,6 +55,8 @@ static kernel_pid_t fpu_owner = KERNEL_PID_UNDEF; //static ucontext_t *cur_ctx, *isr_ctx; +static struct x86_fxsave initial_fpu_state; + int inISR(void) { return x86_in_isr; @@ -169,6 +171,7 @@ char *thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta p->uc_stack.ss_size = stacksize; p->uc_link = &end_context; p->uc_context.flags |= X86_IF; + p->__fxsave = initial_fpu_state; makecontext(p, (makecontext_fun_t) task_func, 1, arg); return (char *) p; @@ -218,6 +221,7 @@ void x86_init_threading(void) makecontext(&end_context, x86_thread_exit, 0); x86_interrupt_handler_set(X86_INT_NM, fpu_used_interrupt); + asm volatile ("fxsave (%0)" :: "r"(&initial_fpu_state)); DEBUG("Threading initialized\n"); }