riscv: integrate the new FPU context switching support

FPU context switching is always performed on demand through the FPU
access exception handler. Actual task switching only grants or denies
FPU access depending on the current FPU owner.

Because RISC-V doesn't have a dedicated FPU access exception, we must
catch the Illegal Instruction exception and look for actual FP opcodes.

There is no longer a need to allocate FPU storage on the stack for every
exception making esf smaller and stack overflows less likely.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2023-01-17 23:32:21 -05:00 committed by Carles Cufí
commit ff07da6ff1
12 changed files with 204 additions and 344 deletions

View file

@ -65,12 +65,9 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
*/
stack_init->mstatus = MSTATUS_DEF_RESTORE;
#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
/* Shared FP mode: enable FPU of threads with K_FP_REGS. */
if ((thread->base.user_options & K_FP_REGS) != 0) {
stack_init->mstatus |= MSTATUS_FS_INIT;
}
thread->callee_saved.fcsr = 0;
#if defined(CONFIG_FPU_SHARING)
/* thread birth happens through the exception return path */
thread->arch.exception_depth = 1;
#elif defined(CONFIG_FPU)
/* Unshared FP mode: enable FPU of each thread. */
stack_init->mstatus |= MSTATUS_FS_INIT;
@ -118,72 +115,6 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
thread->switch_handle = thread;
}
#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
int arch_float_disable(struct k_thread *thread)
{
unsigned int key;
if (thread != _current) {
return -EINVAL;
}
if (arch_is_in_isr()) {
return -EINVAL;
}
/* Ensure a preemptive context switch does not occur */
key = irq_lock();
/* Disable all floating point capabilities for the thread */
thread->base.user_options &= ~K_FP_REGS;
/* Clear the FS bits to disable the FPU. */
__asm__ volatile (
"mv t0, %0\n"
"csrrc x0, mstatus, t0\n"
:
: "r" (MSTATUS_FS_MASK)
);
irq_unlock(key);
return 0;
}
int arch_float_enable(struct k_thread *thread, unsigned int options)
{
unsigned int key;
if (thread != _current) {
return -EINVAL;
}
if (arch_is_in_isr()) {
return -EINVAL;
}
/* Ensure a preemptive context switch does not occur */
key = irq_lock();
/* Enable all floating point capabilities for the thread. */
thread->base.user_options |= K_FP_REGS;
/* Set the FS bits to Initial and clear the fcsr to enable the FPU. */
__asm__ volatile (
"mv t0, %0\n"
"csrrs x0, mstatus, t0\n"
"fscsr x0, x0\n"
:
: "r" (MSTATUS_FS_INIT)
);
irq_unlock(key);
return 0;
}
#endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
#ifdef CONFIG_USERSPACE
/*