arch/armv7-[a|r]: correct the handing of group env switch
This PR resolved 2 issues: 1. CURRENT_REGS is not set correctly on swint handling 2. group env is not changed properly Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
96fa8be5f5
commit
b110c984b1
@ -32,6 +32,7 @@
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "group/group.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@ -54,10 +55,22 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
DEBUGASSERT(regs);
|
||||
/* Nested interrupts are not supported */
|
||||
|
||||
DEBUGASSERT(CURRENT_REGS == NULL);
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* CURRENT_REGS is also used to manage interrupt level context switches.
|
||||
*/
|
||||
|
||||
CURRENT_REGS = regs;
|
||||
|
||||
/* The SYSCALL command is in R0 on entry. Parameters follow in R1..R7 */
|
||||
|
||||
cmd = regs[REG_R0];
|
||||
|
||||
/* Handle the SVCall according to the command in R0 */
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* R0=SYS_restore_context: Restore task context
|
||||
@ -78,8 +91,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(regs);
|
||||
CURRENT_REGS = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(CURRENT_REGS);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -104,7 +117,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
regs = (uint32_t *)regs[REG_R2];
|
||||
CURRENT_REGS = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@ -112,12 +125,37 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
svcerr("ERROR: Bad SYS call: 0x%" PRIx32 "\n", regs[REG_R0]);
|
||||
_alert("Syscall from 0x%" PRIx32 "\n", regs[REG_PC]);
|
||||
CURRENT_REGS = regs;
|
||||
PANIC();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* CURRENT_REGS will have a different value than it did on entry. If an
|
||||
* interrupt level context switch has occurred, then establish the correct
|
||||
* address environment before returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != CURRENT_REGS)
|
||||
{
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
* MMU flushed) and set up the address environment for the new
|
||||
* thread at the head of the ready-to-run list.
|
||||
*/
|
||||
|
||||
group_addrenv(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set CURRENT_REGS to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
regs = (uint32_t *)CURRENT_REGS;
|
||||
CURRENT_REGS = NULL;
|
||||
|
||||
/* Return the last value of curent_regs. This supports context switches
|
||||
* on return from the exception. That capability is only used with the
|
||||
* SYS_context_switch system call.
|
||||
|
@ -35,10 +35,11 @@
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/addrenv.h>
|
||||
|
||||
#include "signal/signal.h"
|
||||
#include "arm.h"
|
||||
#include "addrenv.h"
|
||||
#include "arm.h"
|
||||
#include "arm_internal.h"
|
||||
#include "group/group.h"
|
||||
#include "signal/signal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -165,7 +166,13 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
/* Nested interrupts are not supported */
|
||||
|
||||
DEBUGASSERT(regs);
|
||||
DEBUGASSERT(CURRENT_REGS == NULL);
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* CURRENT_REGS is also used to manage interrupt level context switches.
|
||||
*/
|
||||
|
||||
CURRENT_REGS = regs;
|
||||
|
||||
/* The SYSCALL command is in R0 on entry. Parameters follow in R1..R7 */
|
||||
|
||||
@ -262,8 +269,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(regs);
|
||||
CURRENT_REGS = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(CURRENT_REGS);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -288,7 +295,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
regs = (uint32_t *)regs[REG_R2];
|
||||
CURRENT_REGS = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@ -529,10 +536,37 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* CURRENT_REGS will have a different value than it did on entry. If an
|
||||
* interrupt level context switch has occurred, then establish the correct
|
||||
* address environment before returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != CURRENT_REGS)
|
||||
{
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
* MMU flushed) and set up the address environment for the new
|
||||
* thread at the head of the ready-to-run list.
|
||||
*/
|
||||
|
||||
group_addrenv(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
regs = (uint32_t *)CURRENT_REGS;
|
||||
|
||||
/* Report what happened */
|
||||
|
||||
dump_syscall("Exit", cmd, regs);
|
||||
|
||||
/* Set CURRENT_REGS to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
CURRENT_REGS = NULL;
|
||||
|
||||
/* Return the last value of curent_regs. This supports context switches
|
||||
* on return from the exception. That capability is only used with the
|
||||
* SYS_context_switch system call.
|
||||
|
@ -33,9 +33,10 @@
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
|
||||
#include "signal/signal.h"
|
||||
#include "addrenv.h"
|
||||
#include "arm.h"
|
||||
#include "arm_internal.h"
|
||||
#include "signal/signal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -162,7 +163,13 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
/* Nested interrupts are not supported */
|
||||
|
||||
DEBUGASSERT(regs);
|
||||
DEBUGASSERT(CURRENT_REGS == NULL);
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* CURRENT_REGS is also used to manage interrupt level context switches.
|
||||
*/
|
||||
|
||||
CURRENT_REGS = regs;
|
||||
|
||||
/* The SYSCALL command is in R0 on entry. Parameters follow in R1..R7 */
|
||||
|
||||
@ -259,8 +266,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(regs);
|
||||
CURRENT_REGS = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(CURRENT_REGS);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -285,7 +292,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
regs = (uint32_t *)regs[REG_R2];
|
||||
CURRENT_REGS = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@ -526,10 +533,18 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
regs = (uint32_t *)CURRENT_REGS;
|
||||
|
||||
/* Report what happened */
|
||||
|
||||
dump_syscall("Exit", cmd, regs);
|
||||
|
||||
/* Set CURRENT_REGS to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
CURRENT_REGS = NULL;
|
||||
|
||||
/* Return the last value of curent_regs. This supports context switches
|
||||
* on return from the exception. That capability is only used with the
|
||||
* SYS_context_switch system call.
|
||||
|
Loading…
Reference in New Issue
Block a user