1/* 2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <config.h> 8#include <machine/fpu.h> 9#include <api/failures.h> 10#include <model/statedata.h> 11#include <arch/object/structures.h> 12 13#ifdef CONFIG_HAVE_FPU 14/* Switch the owner of the FPU to the given thread on local core. */ 15void switchLocalFpuOwner(user_fpu_state_t *new_owner) 16{ 17 enableFpu(); 18 if (NODE_STATE(ksActiveFPUState)) { 19 saveFpuState(NODE_STATE(ksActiveFPUState)); 20 } 21 if (new_owner) { 22 NODE_STATE(ksFPURestoresSinceSwitch) = 0; 23 loadFpuState(new_owner); 24 } else { 25 disableFpu(); 26 } 27 NODE_STATE(ksActiveFPUState) = new_owner; 28} 29 30void switchFpuOwner(user_fpu_state_t *new_owner, word_t cpu) 31{ 32#ifdef ENABLE_SMP_SUPPORT 33 if (cpu != getCurrentCPUIndex()) { 34 doRemoteswitchFpuOwner(new_owner, cpu); 35 } else 36#endif /* ENABLE_SMP_SUPPORT */ 37 { 38 switchLocalFpuOwner(new_owner); 39 } 40} 41 42/* Handle an FPU fault. 43 * 44 * This CPU exception is thrown when userspace attempts to use the FPU while 45 * it is disabled. We need to save the current state of the FPU, and hand 46 * it over. */ 47exception_t handleFPUFault(void) 48{ 49 /* If we have already given the FPU to the user, we should not reach here. 50 * This should only be able to occur on CPUs without an FPU at all, which 51 * we presumably are happy to assume will not be running seL4. */ 52 assert(!nativeThreadUsingFPU(NODE_STATE(ksCurThread))); 53 54 /* Otherwise, lazily switch over the FPU. */ 55 switchLocalFpuOwner(&NODE_STATE(ksCurThread)->tcbArch.tcbContext.fpuState); 56 57 return EXCEPTION_NONE; 58} 59 60/* Prepare for the deletion of the given thread. */ 61void fpuThreadDelete(tcb_t *thread) 62{ 63 /* If the thread being deleted currently owns the FPU, switch away from it 64 * so that 'ksActiveFPUState' doesn't point to invalid memory. */ 65 if (nativeThreadUsingFPU(thread)) { 66 switchFpuOwner(NULL, SMP_TERNARY(thread->tcbAffinity, 0)); 67 } 68} 69#endif /* CONFIG_HAVE_FPU */ 70