1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4  */
5 
6 #ifndef FPU_HELPERS_H
7 #define FPU_HELPERS_H
8 
9 #include <arch_helpers.h>
10 #include <assert.h>
11 #include <cpuid.h>
12 #include <stdbool.h>
13 
14 /* The FPU and SIMD register bank is 32 quadword (128 bits) Q registers. */
15 #define FPU_Q_SIZE		16U
16 #define FPU_Q_COUNT		32U
17 
18 /* These defines are needed by assembly code to access the context. */
19 #define FPU_CTX_OFFSET_Q	0U
20 #define FPU_CTX_OFFSET_FPSR	512U
21 #define FPU_CTX_OFFSET_FPCR	520U
22 
23 #ifdef RMM_FPU_USE_AT_REL2
24 #define FPU_ALLOW(expression) \
25 	do { \
26 		assert(fpu_is_my_state_saved(my_cpuid())); \
27 		write_cptr_el2( \
28 			(read_cptr_el2() & \
29 			(~(CPTR_EL2_FPEN_MASK << CPTR_EL2_FPEN_SHIFT))) | \
30 			(CPTR_EL2_FPEN_NO_TRAP_11 << CPTR_EL2_FPEN_SHIFT)); \
31 		isb(); \
32 		expression; \
33 		write_cptr_el2( \
34 			(read_cptr_el2() & \
35 			(~(CPTR_EL2_FPEN_MASK << CPTR_EL2_FPEN_SHIFT))) | \
36 			(CPTR_EL2_FPEN_TRAP_ALL_00 << CPTR_EL2_FPEN_SHIFT)); \
37 		isb(); \
38 	} while (0)
39 
40 #define IS_FPU_ALLOWED() \
41 	(fpu_is_my_state_saved(my_cpuid()) && is_fpen_enabled())
42 
43 #else /* RMM_FPU_USE_AT_REL2 */
44 #define FPU_ALLOW(expression) \
45 	do { \
46 		expression; \
47 	} while (0)
48 
49 #define IS_FPU_ALLOWED() (true)
50 
51 #endif /* RMM_FPU_USE_AT_REL2 */
52 
53 struct fpu_state {
54 	unsigned __int128 q[FPU_Q_COUNT];
55 	unsigned long fpsr;
56 	unsigned long fpcr;
57 };
58 
59 /* Since we use these offsets in assembly code make sure they are correct. */
60 COMPILER_ASSERT(__builtin_offsetof(struct fpu_state, q) ==
61 	FPU_CTX_OFFSET_Q);
62 COMPILER_ASSERT(__builtin_offsetof(struct fpu_state, fpsr) ==
63 	FPU_CTX_OFFSET_FPSR);
64 COMPILER_ASSERT(__builtin_offsetof(struct fpu_state, fpcr) ==
65 	FPU_CTX_OFFSET_FPCR);
66 
67 /*
68  * Save/restore FPU context to/from the `fpu_state` passed as parameter. The FPU
69  * instruction trap needs to be disabled before calling these functions.
70  * Can be used for context switching.
71  */
72 void fpu_save_state(struct fpu_state *fpu);
73 void fpu_restore_state(struct fpu_state *fpu);
74 
75 /*
76  * Save/restore FPU state to/from a per-cpu buffer allocated within the
77  * library. The FPU instruction trap is disabled by this function during the
78  * access to the FPU registers.
79  * These functions are expected to be called before FPU is used by RMM to save
80  * the incoming FPU context.
81  */
82 void fpu_save_my_state(void);
83 void fpu_restore_my_state(void);
84 
85 /*
86  * Return true iff an fpu state is saved in the per-cpu buffer in this library.
87  *
88  * After calling 'fpu_save_my_state' this function returns true. After calling
89  * 'fpu_restore_my_state' this function returns false.
90  */
91 bool fpu_is_my_state_saved(unsigned int cpu_id);
92 
93 #endif /* FPU_HELPERS_H */
94