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 <nuttx/arch.h>
|
||||||
|
|
||||||
#include "arm_internal.h"
|
#include "arm_internal.h"
|
||||||
|
#include "group/group.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
@ -54,10 +55,22 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
{
|
{
|
||||||
uint32_t cmd;
|
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];
|
cmd = regs[REG_R0];
|
||||||
|
|
||||||
|
/* Handle the SVCall according to the command in R0 */
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
/* R0=SYS_restore_context: Restore task context
|
/* R0=SYS_restore_context: Restore task context
|
||||||
@ -78,8 +91,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
* set will determine the restored context.
|
* set will determine the restored context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regs = (uint32_t *)regs[REG_R1];
|
CURRENT_REGS = (uint32_t *)regs[REG_R1];
|
||||||
DEBUGASSERT(regs);
|
DEBUGASSERT(CURRENT_REGS);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -104,7 +117,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
{
|
{
|
||||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||||
*(uint32_t **)regs[REG_R1] = regs;
|
*(uint32_t **)regs[REG_R1] = regs;
|
||||||
regs = (uint32_t *)regs[REG_R2];
|
CURRENT_REGS = (uint32_t *)regs[REG_R2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -112,12 +125,37 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
{
|
{
|
||||||
svcerr("ERROR: Bad SYS call: 0x%" PRIx32 "\n", regs[REG_R0]);
|
svcerr("ERROR: Bad SYS call: 0x%" PRIx32 "\n", regs[REG_R0]);
|
||||||
_alert("Syscall from 0x%" PRIx32 "\n", regs[REG_PC]);
|
_alert("Syscall from 0x%" PRIx32 "\n", regs[REG_PC]);
|
||||||
CURRENT_REGS = regs;
|
|
||||||
PANIC();
|
PANIC();
|
||||||
}
|
}
|
||||||
break;
|
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
|
/* Return the last value of curent_regs. This supports context switches
|
||||||
* on return from the exception. That capability is only used with the
|
* on return from the exception. That capability is only used with the
|
||||||
* SYS_context_switch system call.
|
* SYS_context_switch system call.
|
||||||
|
@ -35,10 +35,11 @@
|
|||||||
#include <nuttx/sched.h>
|
#include <nuttx/sched.h>
|
||||||
#include <nuttx/addrenv.h>
|
#include <nuttx/addrenv.h>
|
||||||
|
|
||||||
#include "signal/signal.h"
|
|
||||||
#include "arm.h"
|
|
||||||
#include "addrenv.h"
|
#include "addrenv.h"
|
||||||
|
#include "arm.h"
|
||||||
#include "arm_internal.h"
|
#include "arm_internal.h"
|
||||||
|
#include "group/group.h"
|
||||||
|
#include "signal/signal.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
@ -165,7 +166,13 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
|
|
||||||
/* Nested interrupts are not supported */
|
/* 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 */
|
/* 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.
|
* set will determine the restored context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regs = (uint32_t *)regs[REG_R1];
|
CURRENT_REGS = (uint32_t *)regs[REG_R1];
|
||||||
DEBUGASSERT(regs);
|
DEBUGASSERT(CURRENT_REGS);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -288,7 +295,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
{
|
{
|
||||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||||
*(uint32_t **)regs[REG_R1] = regs;
|
*(uint32_t **)regs[REG_R1] = regs;
|
||||||
regs = (uint32_t *)regs[REG_R2];
|
CURRENT_REGS = (uint32_t *)regs[REG_R2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -529,10 +536,37 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
break;
|
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 */
|
/* Report what happened */
|
||||||
|
|
||||||
dump_syscall("Exit", cmd, regs);
|
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
|
/* Return the last value of curent_regs. This supports context switches
|
||||||
* on return from the exception. That capability is only used with the
|
* on return from the exception. That capability is only used with the
|
||||||
* SYS_context_switch system call.
|
* SYS_context_switch system call.
|
||||||
|
@ -33,9 +33,10 @@
|
|||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
#include <nuttx/sched.h>
|
#include <nuttx/sched.h>
|
||||||
|
|
||||||
#include "signal/signal.h"
|
#include "addrenv.h"
|
||||||
#include "arm.h"
|
#include "arm.h"
|
||||||
#include "arm_internal.h"
|
#include "arm_internal.h"
|
||||||
|
#include "signal/signal.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
@ -162,7 +163,13 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
|
|
||||||
/* Nested interrupts are not supported */
|
/* 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 */
|
/* 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.
|
* set will determine the restored context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regs = (uint32_t *)regs[REG_R1];
|
CURRENT_REGS = (uint32_t *)regs[REG_R1];
|
||||||
DEBUGASSERT(regs);
|
DEBUGASSERT(CURRENT_REGS);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -285,7 +292,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
{
|
{
|
||||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||||
*(uint32_t **)regs[REG_R1] = regs;
|
*(uint32_t **)regs[REG_R1] = regs;
|
||||||
regs = (uint32_t *)regs[REG_R2];
|
CURRENT_REGS = (uint32_t *)regs[REG_R2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -526,10 +533,18 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regs = (uint32_t *)CURRENT_REGS;
|
||||||
|
|
||||||
/* Report what happened */
|
/* Report what happened */
|
||||||
|
|
||||||
dump_syscall("Exit", cmd, regs);
|
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
|
/* Return the last value of curent_regs. This supports context switches
|
||||||
* on return from the exception. That capability is only used with the
|
* on return from the exception. That capability is only used with the
|
||||||
* SYS_context_switch system call.
|
* SYS_context_switch system call.
|
||||||
|
Loading…
Reference in New Issue
Block a user