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. */
switchLocalFpuOwner(user_fpu_state_t * new_owner)15 void 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
switchFpuOwner(user_fpu_state_t * new_owner,word_t cpu)30 void 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. */
handleFPUFault(void)47 exception_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. */
fpuThreadDelete(tcb_t * thread)61 void 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