Aarch32, FPU: Init fpexc with FPU enabled

On 32-bit ARM the fpexc system register is set by loadFpuState,
which includes the FPU enable/disable bit FPEXC_EN_BIT. This
register is part of the usercontext and needs to be initialised
correctly, otherwise the FPU will be disabled by loadFpuState.

Before, this bug was hidden because the FPU was enabled lazily
after a trap. This bug just caused one extra FPU trap at first
FPU use for each task: The first handleFPUFault would fail to
enable the FPU, causing another FPU trap when user space gets
restarted.

On the second FPU fault, switchLocalFpuOwner calls enableFpu first
and then calls saveFpuState because ksActiveFPUState is set to the
current task's FPU state. Then it gets saved with FPEXC_EN_BIT set
and the task can continue with the FPU actually enabled.

This also means that with the old code, the initial FPEXC state
of each task was equal to the previous active FPU task's.

Signed-off-by: Indan Zupancic <indan@nul.nu>
This commit is contained in:
Indan Zupancic 2025-04-24 20:19:05 +01:00 committed by Gerwin Klein
parent 504f1ccf00
commit 77f5fab0a0
2 changed files with 8 additions and 10 deletions

View file

@ -24,16 +24,6 @@
#define FPSID_SW_BIT 23
#define FPSID_SUBARCH_SHIFT_POS 16
#define FPEXC_EX_BIT 31
#define FPEXC_EN_BIT 30
#if defined(CONFIG_ARM_CORTEX_A7) || defined(CONFIG_ARM_CORTEX_A9)
#define FPEXC_DEX_BIT 29
#endif
#define FPEXC_DEX_BIT 29
#define FPEXC_FP2V_BIT 28
static void clearEnFPEXC(void)
{
word_t fpexc;

View file

@ -32,6 +32,11 @@
| PMODE_IDLE \
| CPSR_EXTRA_FLAGS )
#define FPEXC_EX_BIT 31
#define FPEXC_EN_BIT 30
#define FPEXC_DEX_BIT 29
#define FPEXC_FP2V_BIT 28
/* Offsets within the user context, these need to match the order in
* register_t below */
#define PT_SP (13 * 4)
@ -245,6 +250,9 @@ void Arch_initBreakpointContext(user_context_t *context);
static inline void Arch_initContext(user_context_t *context)
{
context->registers[CPSR] = CPSR_USER;
#ifdef CONFIG_HAVE_FPU
context->fpuState.fpexc = BIT(FPEXC_EN_BIT);
#endif
#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE
Arch_initBreakpointContext(context);
#endif