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