forked from Imagelibrary/rtems
arm: Fix Armv7-M floating-point support
The _ARMV7M_Pendable_service_call() and _ARMV7M_Supervisor_call() work
as a team. The --ef and ++ef is there to preserve the original exception
frame across the jump to and from _ARMV7M_Thread_dispatch().
void _ARMV7M_Pendable_service_call( void )
{
Per_CPU_Control *cpu_self = _Per_CPU_Get();
/*
* We must check here if a thread dispatch is allowed. Right after a
* "msr basepri_max, %[basepri]" instruction an interrupt service may
still
* take place. However, pendable service calls that are activated during
* this interrupt service may be delayed until interrupts are enable
again.
*/
if (
( cpu_self->isr_nest_level |
cpu_self->thread_dispatch_disable_level ) == 0
) {
ARMV7M_Exception_frame *ef;
cpu_self->isr_nest_level = 1;
_ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
_ARMV7M_Trigger_lazy_floating_point_context_save();
At this point, the floating point context should be saved on the
exception frame. The FPCCR.LSPACT bit should be 0, to indicate that lazy
state preservation is no longer active.
ef = (ARMV7M_Exception_frame *) _ARMV7M_Get_PSP();
--ef;
_ARMV7M_Set_PSP( (uint32_t) ef );
This new exception frame is just there to jump to
_ARMV7M_Thread_dispatch(). Here was the problem, that FPCCR.LSPACT was
not set to 1. This resulted in a floating-point context from
uninitialized memory which could corrupt the floating-point state. See
also:
https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/System-Level-Programmers--Model/ARMv7-M-exception-model/Exception-return-behavior?lang=en
/*
* According to "ARMv7-M Architecture Reference Manual" section B1.5.6
* "Exception entry behavior" the return address is half-word aligned.
*/
ef->register_pc = (void *)
((uintptr_t) _ARMV7M_Thread_dispatch & ~((uintptr_t) 1));
ef->register_xpsr = 0x01000000U;
}
}
Close #4923.
This commit is contained in:
committed by
Kinsey Moore
parent
b874f4c99d
commit
e74cea4172
@@ -58,6 +58,7 @@ static void _ARMV7M_Trigger_lazy_floating_point_context_save( void )
|
||||
#ifdef ARM_MULTILIB_VFP
|
||||
__asm__ volatile (
|
||||
"vmov.f32 s0, s0\n"
|
||||
: : : "memory"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
@@ -75,12 +76,22 @@ void _ARMV7M_Pendable_service_call( void )
|
||||
if (
|
||||
( cpu_self->isr_nest_level | cpu_self->thread_dispatch_disable_level ) == 0
|
||||
) {
|
||||
volatile ARMV7M_SCB *scb = _ARMV7M_SCB;
|
||||
ARMV7M_Exception_frame *ef;
|
||||
|
||||
cpu_self->isr_nest_level = 1;
|
||||
|
||||
_ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
|
||||
scb->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
|
||||
_ARMV7M_Trigger_lazy_floating_point_context_save();
|
||||
#ifdef ARM_MULTILIB_VFP
|
||||
/*
|
||||
* Set FPCCR[LSPACT] to mark the lazy state preservation as active. This
|
||||
* prevents that a floating-point context is restored from the
|
||||
* uninitialized exception frame below in the return to
|
||||
* _ARMV7M_Thread_dispatch().
|
||||
*/
|
||||
scb->fpccr |= 0x1;
|
||||
#endif
|
||||
|
||||
ef = (ARMV7M_Exception_frame *) _ARMV7M_Get_PSP();
|
||||
--ef;
|
||||
|
||||
Reference in New Issue
Block a user