Skip to content

kernel: force K_FP_REGS in z_setup_new_thread when FPU_SHARING - #10

Merged
bhuvanchandradv merged 1 commit into
mainfrom
fix/main-sysworkq-fp-regs
Jul 6, 2026
Merged

kernel: force K_FP_REGS in z_setup_new_thread when FPU_SHARING#10
bhuvanchandradv merged 1 commit into
mainfrom
fix/main-sysworkq-fp-regs

Conversation

@bhuvanchandradv

@bhuvanchandradv bhuvanchandradv commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

Fixes the ES0182 lazy-FPU-stacking race window on Cortex-M for all kernel-internal threads (main, sysworkq, idle) when CONFIG_FPU && CONFIG_FPU_SHARING are enabled.

  • GCC >= 9 with -mfloat-abi=hard emits FP instructions in any thread for struct copies and register spills, even without explicit float in source
  • arch_new_thread() reads K_FP_REGS at creation time to size the MPU stack guard — if absent, the guard is sized too small
  • z_arm_mpu_stack_guard_and_fpu_adjust() can only retroactively tag K_FP_REGS at the next context switch, leaving a race window open for any ISR that fires before that switch
  • Fix: OR K_FP_REGS into options at the top of z_setup_new_thread(), before z_init_thread_base() and arch_new_thread() — closes the gap for all threads in one place

Upstream issue: zephyrproject-rtos#108793

Changes

  • kernel/thread.c: add options |= K_FP_REGS under #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) at the top of z_setup_new_thread()

Test plan

  • Build oksbot_base_ctrl_fw with CONFIG_FPU=y, CONFIG_FPU_SHARING=y, CONFIG_HW_STACK_PROTECTION=y — verify no boot crash during boot_banner() / static C++ constructors
  • Flash B0162 and confirm clean boot with no HARD+USAGE+BUS+MPU compound fault
  • Verify sysworkq and main thread both show K_FP_REGS set via GDB k_thread_foreach after boot

When CONFIG_FPU and CONFIG_FPU_SHARING are both enabled, GCC >= 9
with -mfloat-abi=hard emits FP instructions in any translation unit
for struct copies and register spills, regardless of whether the
source code explicitly uses float.  This affects all threads,
including kernel-internal ones like main and sysworkq whose options
are set by the kernel, not the application.

On Cortex-M, arch_new_thread() reads K_FP_REGS at creation time to
size the MPU stack guard (FP_GUARD_EXTRA_SIZE) and set
Z_ARM_MODE_MPU_GUARD_FLOAT_Msk.  Without K_FP_REGS at that point,
the guard is sized too small.  z_arm_mpu_stack_guard_and_fpu_adjust()
can retroactively tag K_FP_REGS at the next context switch, but any
ISR arriving between the thread's first FP instruction and that
switch opens the Cortex-M4 ES0182 lazy-FPU-stacking race window,
corrupting the saved PC and causing a compound HARD+USAGE+BUS+MPU
fault on exception return.

Fix this by unconditionally ORing K_FP_REGS into options at the top
of z_setup_new_thread() when CONFIG_FPU && CONFIG_FPU_SHARING, before
z_init_thread_base() writes user_options and before arch_new_thread()
reads them for guard sizing.  This closes the race for main, sysworkq,
idle, and any future kernel-internal thread in one place without
requiring each call-site to be updated.

Fixes zephyrproject-rtos#108793

Signed-off-by: BhuvanChandra DV <[email protected]>
@bhuvanchandradv bhuvanchandradv self-assigned this Jul 6, 2026
@bhuvanchandradv
bhuvanchandradv merged commit a9255ff into main Jul 6, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants