diff --git a/include/arch/arm/arch/kernel/traps.h b/include/arch/arm/arch/kernel/traps.h index c4bcdba97..14ac692a3 100644 --- a/include/arch/arm/arch/kernel/traps.h +++ b/include/arch/arm/arch/kernel/traps.h @@ -23,4 +23,21 @@ static inline void arch_c_exit_hook(void) { void c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) VISIBLE SECTION(".vectors.text"); +void c_handle_interrupt(void) +VISIBLE SECTION(".vectors.text"); + +void c_handle_undefined_instruction(void) +VISIBLE SECTION(".vectors.text"); + +void c_handle_data_fault(void) +VISIBLE SECTION(".vectors.text"); + +void c_handle_instruction_fault(void) +VISIBLE SECTION(".vectors.text"); + +#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT +void c_handle_vcpu_fault(word_t hsr) +VISIBLE SECTION(".vectors.text"); +#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */ + #endif /* __KERNEL_ARM_TRAPS_H */ diff --git a/include/benchmark_track.h b/include/benchmark_track.h index 7a316b77e..ed690727a 100644 --- a/include/benchmark_track.h +++ b/include/benchmark_track.h @@ -21,6 +21,7 @@ #include #if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) +#define TRACK_KERNEL_ENTRIES 1 #ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES /** * Calculate the maximum number of kernel entries that can be tracked, diff --git a/include/kernel/traps.h b/include/kernel/traps.h index ca55dfdc1..33f076565 100644 --- a/include/kernel/traps.h +++ b/include/kernel/traps.h @@ -18,7 +18,8 @@ /* This C function should be the first thing called from C after entry from * assembly. It provides a single place to do any entry work that is not * done in assembly for various reasons */ -static inline void c_entry_hook(void) { +static inline void c_entry_hook(void) +{ arch_c_entry_hook(); #if defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) || defined(CONFIG_BENCHMARK_TRACK_UTILISATION) ksEnter = timestamp(); @@ -29,14 +30,12 @@ static inline void c_entry_hook(void) { * the kernel (be it to assembly or returning to user space). It provides * a place to provide any additional instrumentation or functionality * in C before leaving the kernel */ -static inline void c_exit_hook(void) { +static inline void c_exit_hook(void) +{ #ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES benchmark_track_exit(); #endif /* CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES */ arch_c_exit_hook(); } -void c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) -VISIBLE SECTION(".vectors.text"); - #endif /* __KERNEL_TRAPS_H */ diff --git a/libsel4/include/sel4/benchmark_track_types.h b/libsel4/include/sel4/benchmark_track_types.h index ffbb6dea1..e812e51d8 100644 --- a/libsel4/include/sel4/benchmark_track_types.h +++ b/libsel4/include/sel4/benchmark_track_types.h @@ -24,7 +24,9 @@ typedef enum { Entry_UnknownSyscall, Entry_UserLevelFault, Entry_VMFault, - Entry_Syscall + Entry_Syscall, + Entry_UnimplementedDevice, + Entry_VCPUFault } entry_type_t; /** diff --git a/src/api/syscall.c b/src/api/syscall.c index ca1db757c..11747e8d2 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -39,13 +39,7 @@ handleInterruptEntry(void) { irq_t irq; - c_entry_hook(); - irq = getActiveIRQ(); -#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) - ksKernelEntry.path = Entry_Interrupt; - ksKernelEntry.word = irq; -#endif /* DEBUG */ if (irq != irqInvalid) { handleInterrupt(irq); @@ -59,8 +53,6 @@ handleInterruptEntry(void) schedule(); activateThread(); - c_exit_hook(); - return EXCEPTION_NONE; } @@ -68,9 +60,6 @@ exception_t handleUnknownSyscall(word_t w) { #ifdef CONFIG_DEBUG_BUILD - ksKernelEntry.path = Entry_UnknownSyscall; - ksKernelEntry.word = w; - if (w == SysDebugPutChar) { kernel_putchar(getRegister(ksCurThread, capRegister)); return EXCEPTION_NONE; @@ -190,22 +179,12 @@ handleUnknownSyscall(word_t w) exception_t handleUserLevelFault(word_t w_a, word_t w_b) { - c_entry_hook(); -#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) - ksKernelEntry.path = Entry_UserLevelFault; - ksKernelEntry.word = w_a; -#endif /* DEBUG */ - current_fault = fault_user_exception_new(w_a, w_b); handleFault(ksCurThread); schedule(); activateThread(); -#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES - benchmark_track_exit(); -#endif - return EXCEPTION_NONE; } @@ -213,11 +192,6 @@ exception_t handleVMFaultEvent(vm_fault_type_t vm_faultType) { exception_t status; - c_entry_hook(); -#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) - ksKernelEntry.path = Entry_VMFault; - ksKernelEntry.word = vm_faultType; -#endif /* DEBUG */ status = handleVMFault(ksCurThread, vm_faultType); if (status != EXCEPTION_NONE) { @@ -227,8 +201,6 @@ handleVMFaultEvent(vm_fault_type_t vm_faultType) schedule(); activateThread(); - c_exit_hook(); - return EXCEPTION_NONE; } @@ -252,10 +224,6 @@ handleInvocation(bool_t isCall, bool_t isBlocking) /* faulting section */ lu_ret = lookupCapAndSlot(thread, cptr); -#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) - ksKernelEntry.is_fastpath = false; -#endif - if (unlikely(lu_ret.status != EXCEPTION_NONE)) { userError("Invocation of invalid cap #%lu.", cptr); current_fault = fault_cap_fault_new(cptr, false); diff --git a/src/arch/arm/32/hyp_traps.S b/src/arch/arm/32/hyp_traps.S index 8546caa34..1b82a9d83 100644 --- a/src/arch/arm/32/hyp_traps.S +++ b/src/arch/arm/32/hyp_traps.S @@ -95,30 +95,6 @@ END_FUNC(arm_vector_table) #define HSREC_DATA_ABORT 0x24 #define HSRIL32 (1 << 25) -/* Helper to return to userland. */ -.macro RET_TO_USER, cur_thread_reg - /* cur_thread_reg should contain the address of ksCurThread. */ - /* Set stack pointer to point at the r0 of the user context. */ - ldr sp, [\cur_thread_reg] - /* Pop user registers */ - pop {r0-r12} - /* Retore the user stack pointer */ - pop {lr} - msr sp_usr, lr - - /* prepare the eception return lr */ - ldr lr, [sp, #4] - msr elr_hyp, lr - /* prepare the user status register */ - ldr lr, [sp, #8] - msr spsr_hyp, lr - - /* Finally, pop our LR */ - pop {lr} - /* Return to user */ - eret -.endm - .macro EX_ENTRY /* Create some scratch space */ push {lr} @@ -133,6 +109,16 @@ END_FUNC(arm_vector_table) push {lr} .endm +/* Prepare to enter the kernel */ +.macro PUSH_STACK + /* store FaultInstruction */ + str lr, [sp, #(PT_FaultInstruction - PT_SP)] + /* Stack all user registers */ + push {r0-r12} + /* Load the kernel's real stack pointer */ + mov sp, #(PPTR_KERNEL_STACK_TOP) +.endm + /******************************** *** Traps taken to HYP mode *** ********************************/ @@ -155,95 +141,36 @@ BEGIN_FUNC(arm_hyp_trap) beq arm_undefined_inst /** Everything else is assumed to be a VCPU trap **/ - - /* Store FaultInstruction */ mrs lr, elr_hyp - str lr, [sp, #(PT_FaultInstruction - PT_SP)] - /* Stack all user registers */ - push {r0-r12} - /* Load the kernel's real stack pointer */ - mov sp, #(PPTR_KERNEL_STACK_TOP) - - /* Call out to the user */ - ldr r7, =ksCurThread + PUSH_STACK mrc HSR(r0) - blx handleVCPUFault - - /* Exception return */ - RET_TO_USER r7 + b c_handle_vcpu_fault END_FUNC(arm_hyp_trap) BEGIN_FUNC(arm_undefined_inst) - /* Store FaultInstruction */ mrs lr, elr_hyp - str lr, [sp, #(PT_FaultInstruction - PT_SP)] - /* Stack all user registers */ - push {r0-r12} - /* Load the kernel's real stack pointer */ - mov sp, #(PPTR_KERNEL_STACK_TOP) - - /* Call out to the user */ - ldr r7, =ksCurThread - mov r0, #0 - mov r1, #0 - blx handleUserLevelFault - - /* Exception return */ - RET_TO_USER r7 + PUSH_STACK + b c_handle_undefined_instruction END_FUNC(arm_undefined_inst) BEGIN_FUNC(arm_prefetch_abort) - /* Store FaultInstruction */ mrs lr, elr_hyp - str lr, [sp, #(PT_FaultInstruction - PT_SP)] - /* Stack all user registers */ - push {r0-r12} - /* Load the kernel's real stack pointer */ - mov sp, #(PPTR_KERNEL_STACK_TOP) - - /* Call out to the user */ - ldr r7, =ksCurThread - mov r0, #seL4_InstructionFault - blx handleVMFaultEvent - - /* Exception return */ - RET_TO_USER r7 + PUSH_STACK + b c_handle_instruction_fault END_FUNC(arm_prefetch_abort) BEGIN_FUNC(arm_data_abort) - /* Store FaultInstruction */ mrs lr, elr_hyp - str lr, [sp, #(PT_FaultInstruction - PT_SP)] - /* Stack all user registers */ - push {r0-r12} - /* Load the kernel's real stack pointer */ - mov sp, #(PPTR_KERNEL_STACK_TOP) - - /* Call out to the user */ - ldr r7, =ksCurThread - mov r0, #seL4_DataFault - blx handleVMFaultEvent - - /* Exception return */ - RET_TO_USER r7 + PUSH_STACK + b c_handle_data_fault END_FUNC(arm_data_abort) BEGIN_FUNC(arm_syscall) - /* Store FaultInstruction */ mrs lr, elr_hyp sub lr, lr, #4 - str lr, [sp, #(PT_FaultInstruction - PT_SP)] - - /* Stack all user registers */ - push {r0-r12} - - /* Load the kernel's real stack pointer */ - mov sp, #(PPTR_KERNEL_STACK_TOP) - - /* Load system call number as a c_handle_syscall argument. r0 and r1 are passed - * unmodified (cptr and msgIngo respectively). - */ + PUSH_STACK + /* r0: cptr, r1: msgInfo, r2: syscallNo */ mov r2, r7 b c_handle_syscall END_FUNC(arm_syscall) @@ -295,20 +222,9 @@ END_FUNC(arm_hyp_syscall) BEGIN_FUNC(arm_hyp_irq_exception) EX_ENTRY - - /* Store FaultInstruction */ mrs lr, elr_hyp - str lr, [sp, #(PT_FaultInstruction - PT_SP)] - /* Stack all user registers */ - push {r0-r12} - - /* Handle the exception */ - ldr r7, =ksCurThread - mov sp, #(PPTR_KERNEL_STACK_TOP) - blx handleInterruptEntry - - /* Return to the user */ - RET_TO_USER r7 + PUSH_STACK + b c_handle_interrupt END_FUNC(arm_hyp_irq_exception) BEGIN_FUNC(arm_hyp_reset_exception) diff --git a/src/arch/arm/32/traps.S b/src/arch/arm/32/traps.S index 2ec2f419c..0cca9ce8b 100644 --- a/src/arch/arm/32/traps.S +++ b/src/arch/arm/32/traps.S @@ -38,20 +38,6 @@ END_FUNC(arm_vector_table) #include #include -/* Helper to return to userland. */ -.macro RET_TO_USER, cur_thread_reg - /* cur_thread_reg should contain the address of ksCurThread. */ - /* Set stack pointer to point at the LR_svc of the user context. */ - ldr sp, [\cur_thread_reg] - add sp, sp, #PT_LR_svc - - /* Unstack user registers */ - ldmdb sp, {r0-lr}^ - - /* Jump to user NextPC and restore user CPSR */ - rfeia sp -.endm - BEGIN_FUNC(arm_undefined_inst_exception) /* Full save/restore, documented in arm_swi_syscall */ srsia #PMODE_SUPERVISOR @@ -66,15 +52,7 @@ BEGIN_FUNC(arm_undefined_inst_exception) sub r8, r8, #4 str r8, [sp, #(PT_FaultInstruction - PT_LR_svc)] ldr sp, =(PPTR_KERNEL_STACK_TOP) - - ldr r7, =ksCurThread - - /* There's only one user-level fault on ARM, and the code is (0,0) */ - mov r0, #0 - mov r1, #0 - blx handleUserLevelFault - - RET_TO_USER r7 + b c_handle_undefined_instruction #endif END_FUNC(arm_undefined_inst_exception) @@ -98,7 +76,7 @@ BEGIN_FUNC(arm_swi_syscall) ldr sp, =(PPTR_KERNEL_STACK_TOP) /* Load system call number as a c_handle_syscall argument. r0 and r1 are passed - * unmodified (cptr and msgInfo respectively). + * unmodified (cptr and msgInfo) respectively. */ mov r2, r7 b c_handle_syscall @@ -127,11 +105,7 @@ BEGIN_FUNC(arm_prefetch_abort_exception) str r8, [sp, #(PT_FaultInstruction - PT_LR_svc)] ldr sp, =(PPTR_KERNEL_STACK_TOP) - ldr r7, =ksCurThread - mov r0, #seL4_InstructionFault - blx handleVMFaultEvent - - RET_TO_USER r7 + b c_handle_instruction_fault kernel_prefetch_fault: #ifdef DEBUG @@ -175,10 +149,8 @@ BEGIN_FUNC(arm_data_abort_exception) ldr sp, =(PPTR_KERNEL_STACK_TOP) ldr r7, =ksCurThread - mov r0, #seL4_DataFault - blx handleVMFaultEvent + b c_handle_data_fault - RET_TO_USER r7 kernel_data_fault: #ifdef DEBUG @@ -207,12 +179,8 @@ BEGIN_FUNC(arm_irq_exception) sub r8, r8, #4 str r8, [sp] str r8, [sp, #(PT_FaultInstruction - PT_LR_svc)] - - ldr r7, =ksCurThread ldr sp, =(PPTR_KERNEL_STACK_TOP) - blx handleInterruptEntry - - RET_TO_USER r7 + b c_handle_interrupt END_FUNC(arm_irq_exception) BEGIN_FUNC(arm_reset_exception) diff --git a/src/arch/arm/c_traps.c b/src/arch/arm/c_traps.c index 6ab522721..c1cabb359 100644 --- a/src/arch/arm/c_traps.c +++ b/src/arch/arm/c_traps.c @@ -10,14 +10,83 @@ #include #include +#include +#include #include +#include #include #include /** DONT_TRANSLATE */ -void NORETURN slowpath(syscall_t syscall) +void VISIBLE NORETURN +c_handle_undefined_instruction(void) { + c_entry_hook(); + +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_UserLevelFault; + ksKernelEntry.word = getRegister(ksCurThread, LR_svc); +#endif + + /* There's only one user-level fault on ARM, and the code is (0,0) */ + handleUserLevelFault(0, 0); + restore_user_context(); + UNREACHABLE(); +} + +/** DONT_TRANSLATE */ +static inline void NORETURN +c_handle_vm_fault(vm_fault_type_t type) +{ + c_entry_hook(); + +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_VMFault; + ksKernelEntry.word = getRegister(ksCurThread, LR_svc); +#endif + + handleVMFaultEvent(type); + restore_user_context(); + UNREACHABLE(); +} + +/** DONT_TRANSLATE */ +void VISIBLE NORETURN +c_handle_data_fault(void) +{ + c_handle_vm_fault(seL4_DataFault); +} + +/** DONT_TRANSLATE */ +void VISIBLE NORETURN +c_handle_instruction_fault(void) +{ + c_handle_vm_fault(seL4_InstructionFault); +} + +/** DONT_TRANSLATE */ +void VISIBLE NORETURN +c_handle_interrupt(void) +{ + c_entry_hook(); + +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_Interrupt; + ksKernelEntry.word = getActiveIRQ(); +#endif + + handleInterruptEntry(); + restore_user_context(); +} + +/** DONT_TRANSLATE */ +void NORETURN +slowpath(syscall_t syscall) +{ +#ifdef TRACK_KERNEL_ENTIRES + ksEntry.is_fastpath = 0; +#endif /* TRACK KERNEL ENTRIES */ handleSyscall(syscall); restore_user_context(); @@ -25,11 +94,13 @@ void NORETURN slowpath(syscall_t syscall) } /** DONT_TRANSLATE */ -void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) +void VISIBLE +c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) { c_entry_hook(); -#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) +#if TRACK_KERNEL_ENTRIES benchmark_debug_syscall_start(cptr, msgInfo, syscall); + ksKernelEntry.is_fastpath = 1; #endif /* DEBUG */ #ifdef CONFIG_FASTPATH @@ -43,6 +114,10 @@ void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) #endif /* CONFIG_FASTPATH */ if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) { +#ifdef TRACK_KERNEL_ENTIRES + ksKernelEntry.path = Entry_UnknownSyscall; + /* ksKernelEntry.word word is already set to syscall */ +#endif /* TRACK_KERNEL_ENTRIES */ handleUnknownSyscall(syscall); restore_user_context(); UNREACHABLE(); @@ -51,3 +126,20 @@ void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) UNREACHABLE(); } } + +#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT +/** DONT_TRANSLATE */ +VISIBLE NORETURN void +c_handle_vcpu_fault(word_t hsr) +{ + c_entry_hook(); + +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_VCPUFault; + ksKernelEntry.word = hsr; +#endif + handleVCPUFault(hsr); + restore_user_context(); + UNREACHABLE(); +} +#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */ diff --git a/src/arch/arm/object/vcpu.c b/src/arch/arm/object/vcpu.c index ccbac7dc3..82063e934 100644 --- a/src/arch/arm/object/vcpu.c +++ b/src/arch/arm/object/vcpu.c @@ -596,12 +596,10 @@ invokeVCPUSetTCB(vcpu_t *vcpu, tcb_t *tcb) void handleVCPUFault(word_t hsr) { - c_entry_hook(); current_fault = fault_vcpu_fault_new(hsr); handleFault(ksCurThread); schedule(); activateThread(); - c_exit_hook(); } #endif diff --git a/src/arch/x86/c_traps.c b/src/arch/x86/c_traps.c index 148f2b59d..44425c72f 100644 --- a/src/arch/x86/c_traps.c +++ b/src/arch/x86/c_traps.c @@ -18,22 +18,38 @@ #include #include -void VISIBLE c_handle_interrupt(int irq, int syscall) +/** DONT_TRANSLATE */ +void VISIBLE +c_handle_interrupt(int irq, int syscall) { - /* for annoying reasons we cannot currently consider this the C entry - * point as we would like to call various functions that are considered - * as entry points from the point of view of the arm code. Therefore - * we are *not* calling c_entry_hook here */ + c_entry_hook(); if (irq == int_unimpl_dev) { handleUnimplementedDevice(); +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_UnimplementedDevice; + ksKernelEntry.word = irq; +#endif } else if (irq == int_page_fault) { /* Error code is in Error. Pull out bit 5, which is whether it was instruction or data */ - handleVMFaultEvent((ksCurThread->tcbArch.tcbContext.registers[Error] >> 4) & 1); + vm_fault_type_t type = (ksCurThread->tcbArch.tcbContext.registers[Error] >> 4u) & 1u; +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_VMFault; + ksKernelEntry.word = type; +#endif + handleVMFaultEvent(type); } else if (irq < int_irq_min) { +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_UserLevelFault; + ksKernelEntry.word = irq; +#endif handleUserLevelFault(irq, ksCurThread->tcbArch.tcbContext.registers[Error]); } else if (likely(irq < int_trap_min)) { x86KScurInterrupt = irq; +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_Interrupt; + ksKernelEntry.word = irq; +#endif handleInterruptEntry(); } else if (irq == int_spurious) { /* fall through to restore_user_context and do nothing */ @@ -45,14 +61,16 @@ void VISIBLE c_handle_interrupt(int irq, int syscall) ksCurThread->tcbArch.tcbContext.registers[FaultIP] -= 2; /* trap number is MSBs of the syscall number and the LSBS of EAX */ sys_num = (irq << 24) | (syscall & 0x00ffffff); - /* in this case we are calling a function that is *not* - * an entry point */ - c_entry_hook(); +#ifdef TRACK_KERNEL_ENTIRES + ksKernelEntry.path = Entry_UnknownSyscall; + ksKernelEntry.word = sys_num; +#endif handleUnknownSyscall(sys_num); } restore_user_context(); } +/** DONT_TRANSLATE */ void NORETURN slowpath(syscall_t syscall) { @@ -61,21 +79,32 @@ slowpath(syscall_t syscall) ksCurThread->tcbArch.tcbContext.registers[NextIP] += 2; /* check for undefined syscall */ if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) { +#ifdef TRACK_KERNEL_ENTIRES + ksKernelEntry.path = Entry_UnknownSyscall; + /* ksKernelEntry.word word is already set to syscall */ +#endif /* TRACK_KERNEL_ENTRIES */ handleUnknownSyscall(syscall); } else { +#ifdef TRACK_KERNEL_ENTIRES + ksEntry.is_fastpath = 0; +#endif /* TRACK KERNEL ENTRIES */ handleSyscall(syscall); } restore_user_context(); + UNREACHABLE(); } -void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) +/** DONT_TRANSLATE */ +void VISIBLE +c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall) { c_entry_hook(); -#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) +#ifdef TRACK_KERNEL_ENTRIES benchmark_debug_syscall_start(cptr, msgInfo, syscall); -#endif /* DEBUG */ + ksKernelEntry.is_fastpath = 1; +#endif /* TRACK_KERNEL_ENTRIES */ #ifdef CONFIG_FASTPATH if (syscall == SysCall) { diff --git a/src/arch/x86/machine/fpu.c b/src/arch/x86/machine/fpu.c index 10213231c..24625a99d 100644 --- a/src/arch/x86/machine/fpu.c +++ b/src/arch/x86/machine/fpu.c @@ -57,7 +57,6 @@ switchFpuOwner(tcb_t *new_owner) VISIBLE exception_t handleUnimplementedDevice(void) { - c_entry_hook(); /* * If we have already given the FPU to the user, we should not reach here. *