Need to enable FIQ in initial task state; Improve H32/64 test in IRQ handling
This commit is contained in:
parent
40b7ddf68e
commit
0a134f0158
@ -44,7 +44,9 @@
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
@ -93,7 +95,7 @@
|
||||
* The FPU provides an extension register file containing 32 single-
|
||||
* precision registers. These can be viewed as:
|
||||
*
|
||||
* - Sixteen 64-bit doubleword registers, D0-D15
|
||||
* - Sixteen 64-bit double word registers, D0-D15
|
||||
* - Thirty-two 32-bit single-word registers, S0-S31
|
||||
* S<2n> maps to the least significant half of D<n>
|
||||
* S<2n+1> maps to the most significant half of D<n>.
|
||||
@ -190,8 +192,7 @@
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This struct defines the way the registers are stored. We
|
||||
* need to save:
|
||||
/* This struct defines the way the registers are stored. We need to save:
|
||||
*
|
||||
* 1 CPSR
|
||||
* 7 Static registers, v1-v7 (aka r4-r10)
|
||||
@ -213,16 +214,14 @@
|
||||
#ifndef __ASSEMBLY__
|
||||
struct xcptcontext
|
||||
{
|
||||
/* The following function pointer is non-zero if there
|
||||
* are pending signals to be processed.
|
||||
/* The following function pointer is non-zero if there are pending signals
|
||||
* to be processed.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
void *sigdeliver; /* Actual type is sig_deliver_t */
|
||||
|
||||
/* These are saved copies of LR and CPSR used during
|
||||
* signal processing.
|
||||
*/
|
||||
/* These are saved copies of LR and CPSR used during signal processing. */
|
||||
|
||||
uint32_t saved_pc;
|
||||
uint32_t saved_cpsr;
|
||||
@ -233,7 +232,7 @@ struct xcptcontext
|
||||
uint32_t regs[XCPTCONTEXT_REGS];
|
||||
|
||||
/* Extra fault address register saved for common paging logic. In the
|
||||
* case of the prefetch abort, this value is the same as regs[REG_R15];
|
||||
* case of the pre-fetch abort, this value is the same as regs[REG_R15];
|
||||
* For the case of the data abort, this value is the value of the fault
|
||||
* address register (FAR) at the time of data abort exception.
|
||||
*/
|
||||
@ -328,18 +327,19 @@ static inline void irqrestore(irqstate_t flags)
|
||||
* Public Variables
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -185,7 +185,7 @@
|
||||
.type __start, #function
|
||||
|
||||
__start:
|
||||
/* Make sure that we are in SVC mode with all IRQs disabled */
|
||||
/* Make sure that we are in SVC mode with IRQs and FIQs disabled */
|
||||
|
||||
mov r0, #(PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT)
|
||||
msr cpsr_c, r0
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/armv7-a/arm_initialstate.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2013-2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -68,13 +68,13 @@
|
||||
* Name: up_initial_state
|
||||
*
|
||||
* Description:
|
||||
* A new thread is being started and a new TCB
|
||||
* has been created. This function is called to initialize
|
||||
* the processor specific portions of the new TCB.
|
||||
* A new thread is being started and a new TCB has been created. This
|
||||
* function is called to initialize the processor specific portions of
|
||||
* the new TCB.
|
||||
*
|
||||
* This function must setup the intial architecture registers
|
||||
* and/or stack so that execution will begin at tcb->start
|
||||
* on the next context switch.
|
||||
* This function must setup the initial architecture registers and/or
|
||||
* stack so that execution will begin at tcb->start on the next context
|
||||
* switch.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -89,11 +89,11 @@ void up_initial_state(struct tcb_s *tcb)
|
||||
|
||||
/* Save the initial stack pointer */
|
||||
|
||||
xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr;
|
||||
xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr;
|
||||
|
||||
/* Save the task entry point */
|
||||
|
||||
xcp->regs[REG_PC] = (uint32_t)tcb->start;
|
||||
xcp->regs[REG_PC] = (uint32_t)tcb->start;
|
||||
|
||||
/* If this task is running PIC, then set the PIC base register to the
|
||||
* address of the allocated D-Space region.
|
||||
@ -119,28 +119,39 @@ void up_initial_state(struct tcb_s *tcb)
|
||||
{
|
||||
/* It is a kernel thread.. set supervisor mode */
|
||||
|
||||
cpsr = PSR_MODE_SVC | PSR_F_BIT;
|
||||
cpsr = PSR_MODE_SVC;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It is a normal task or a pthread. Set user mode */
|
||||
|
||||
cpsr = PSR_MODE_USR | PSR_F_BIT;
|
||||
cpsr = PSR_MODE_USR;
|
||||
}
|
||||
#else
|
||||
/* If the kernel build is not selected, then all threads run in
|
||||
* supervisor-mode.
|
||||
*/
|
||||
|
||||
cpsr = PSR_MODE_SVC | PSR_F_BIT;
|
||||
cpsr = PSR_MODE_SVC;
|
||||
#endif
|
||||
|
||||
/* Enable or disable interrupts, based on user configuration */
|
||||
|
||||
# ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
cpsr |= PSR_I_BIT;
|
||||
# endif
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
/* Disable interrupts (both IRQs and FIQs) */
|
||||
|
||||
xcp->regs[REG_CPSR] = cpsr;
|
||||
cpsr |= (PSR_I_BIT | PSR_F_BIT);
|
||||
|
||||
#else /* CONFIG_SUPPRESS_INTERRUPTS */
|
||||
/* Leave IRQs enabled (Also FIQs if CONFIG_ARMV7A_DECODEFIQ is selected) */
|
||||
|
||||
#ifndef CONFIG_ARMV7A_DECODEFIQ
|
||||
|
||||
cpsr |= PSR_F_BIT;
|
||||
|
||||
#endif /* !CONFIG_ARMV7A_DECODEFIQ */
|
||||
#endif /* CONFIG_SUPPRESS_INTERRUPTS */
|
||||
|
||||
xcp->regs[REG_CPSR] = cpsr;
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@
|
||||
.type __start, #function
|
||||
|
||||
__start:
|
||||
/* Make sure that we are in SVC mode with all IRQs disabled */
|
||||
/* Make sure that we are in SVC mode with IRQs and FIQs disabled */
|
||||
|
||||
mov r0, #(PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT)
|
||||
msr cpsr_c, r0
|
||||
|
@ -115,16 +115,16 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
/* First, handle some special cases when the signal is
|
||||
* being delivered to the currently executing task.
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
sdbg("rtcb=0x%p current_regs=0x%p\n", g_readytorun.head, current_regs);
|
||||
|
||||
if (tcb == (struct tcb_s*)g_readytorun.head)
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and
|
||||
* a task is signalling itself for some reason.
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signalling itself for some reason.
|
||||
*/
|
||||
|
||||
if (!current_regs)
|
||||
@ -134,16 +134,16 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
sigdeliver(tcb);
|
||||
}
|
||||
|
||||
/* CASE 2: We are in an interrupt handler AND the
|
||||
* interrupted task is the same as the one that
|
||||
* must receive the signal, then we will have to modify
|
||||
* the return state as well as the state in the TCB.
|
||||
/* CASE 2: We are in an interrupt handler AND the interrupted
|
||||
* task is the same as the one that must receive the signal, then
|
||||
* we will have to modify the return state as well as the state
|
||||
* in the TCB.
|
||||
*
|
||||
* Hmmm... there looks like a latent bug here: The following
|
||||
* logic would fail in the strange case where we are in an
|
||||
* interrupt handler, the thread is signalling itself, but
|
||||
* a context switch to another task has occurred so that
|
||||
* current_regs does not refer to the thread at g_readytorun.head!
|
||||
* Hmmm... there looks like a latent bug here: The following logic
|
||||
* would fail in the strange case where we are in an interrupt
|
||||
* handler, the thread is signalling itself, but a context switch
|
||||
* to another task has occurred so that current_regs does not
|
||||
* refer to the thread at g_readytorun.head!
|
||||
*/
|
||||
|
||||
else
|
||||
@ -162,27 +162,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
*/
|
||||
|
||||
current_regs[REG_PC] = (uint32_t)up_sigdeliver;
|
||||
current_regs[REG_CPSR] = PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT;
|
||||
current_regs[REG_CPSR] = (PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT);
|
||||
|
||||
/* And make sure that the saved context in the TCB
|
||||
* is the same as the interrupt return context.
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
up_savestate(tcb->xcp.regs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, we are (1) signaling a task is not running
|
||||
* from an interrupt handler or (2) we are not in an
|
||||
* interrupt handler and the running task is signalling
|
||||
* some non-running task.
|
||||
/* Otherwise, we are (1) signaling a task is not running from an
|
||||
* interrupt handler or (2) we are not in an interrupt handler and the
|
||||
* running task is signalling some non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return lr and cpsr and one scratch register
|
||||
* These will be restored by the signal trampoline after
|
||||
* the signals have been delivered.
|
||||
/* Save the return lr and cpsr and one scratch register. These
|
||||
* will be restored by the signal trampoline after the signals
|
||||
* have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
@ -194,7 +193,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT);
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
|
@ -163,10 +163,10 @@
|
||||
|
||||
/* Interrupt Pending Register 0-3 */
|
||||
|
||||
#define AIC_IPR0(pid) (1 << (pid))
|
||||
#define AIC_IPR1(pid) (1 << ((pid) - 32)
|
||||
#define AIC_IPR2(pid) (1 << ((pid) - 64)
|
||||
#define AIC_IPR3(pid) (1 << ((pid) - 96)
|
||||
#define AIC_IPR0(pid) (1 << (pid))
|
||||
#define AIC_IPR1(pid) (1 << ((pid) - 32)
|
||||
#define AIC_IPR2(pid) (1 << ((pid) - 64)
|
||||
#define AIC_IPR3(pid) (1 << ((pid) - 96)
|
||||
|
||||
/* Interrupt Mask Register */
|
||||
|
||||
@ -220,15 +220,15 @@
|
||||
|
||||
/* Write Protect Mode Register */
|
||||
|
||||
#define AIC_WPMR_WPEN (1 << 0) /* Bit 0: Write Protect Enable */
|
||||
#define AIC_WPMR_WPKEY_SHIFT (8) /* Bits 8-31: Write Protect KEY */
|
||||
#define AIC_WPMR_WPKEY_MASK (0x00ffffff << AIC_WPMR_WPKEY_SHIFT)
|
||||
# define AIC_WPMR_WPKEY (0x00414943 << AIC_WPMR_WPKEY_SHIFT)
|
||||
#define AIC_WPMR_WPEN (1 << 0) /* Bit 0: Write Protect Enable */
|
||||
#define AIC_WPMR_WPKEY_SHIFT (8) /* Bits 8-31: Write Protect KEY */
|
||||
#define AIC_WPMR_WPKEY_MASK (0x00ffffff << AIC_WPMR_WPKEY_SHIFT)
|
||||
# define AIC_WPMR_WPKEY (0x00414943 << AIC_WPMR_WPKEY_SHIFT)
|
||||
|
||||
/* Write Protect Status Register */
|
||||
|
||||
#define AIC_WPSR_WPVS (1 << 0) /* Bit 0: Write Protect Violation Status */
|
||||
#define AIC_WPSR_WPVSRC_SHIFT (8) /* Bits 8-23: Write Protect Violation Source */
|
||||
#define AIC_WPSR_WPVSRC_MASK (0x0000ffff << AIC_WPSR_WPVSRC_SHIFT)
|
||||
#define AIC_WPSR_WPVS (1 << 0) /* Bit 0: Write Protect Violation Status */
|
||||
#define AIC_WPSR_WPVSRC_SHIFT (8) /* Bits 8-23: Write Protect Violation Source */
|
||||
#define AIC_WPSR_WPVSRC_MASK (0x0000ffff << AIC_WPSR_WPVSRC_SHIFT)
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_AIC_H */
|
||||
|
@ -52,6 +52,27 @@
|
||||
|
||||
#ifdef ATSAMA5D4
|
||||
# define H64MX_DDR_SLAVE_PORT0 3
|
||||
|
||||
/* These are bits maps of PIDs in the H64MX SPSELR registers. These are used by
|
||||
* application code to quickly determine if a given PID is served by H32MX or H64MX
|
||||
* which, in turn, is needed to know if the peripheral secured in SPSELR).
|
||||
*
|
||||
* NOTE that these hard-code bit values must match the PID assignments in
|
||||
* arch/arm/include/sama5/sama5*_irq.h.
|
||||
*/
|
||||
|
||||
/* ARM=2, XDMAC0=8, CPKCC=10, AESB=13, MPDDRC=16, MATRIX0=18, VDEC=19 */
|
||||
|
||||
# define H64MX_SPSELR0_PIDS 0x000d2504
|
||||
|
||||
/* XDMAC1=50, LCDC=51, ISI=52 */
|
||||
|
||||
# define H64MX_SPSELR1_PIDS 0x001c0000
|
||||
|
||||
/* L2CC=67 */
|
||||
|
||||
# define H64MX_SPSELR2_PIDS 0x00000008
|
||||
|
||||
#endif
|
||||
|
||||
/* MATRIX register offsets **************************************************************/
|
||||
|
@ -94,6 +94,19 @@ static const uint8_t g_srctype[SCRTYPE_NTYPES] =
|
||||
0, 0, 1, 1, 2, 3
|
||||
};
|
||||
|
||||
/* This is an arry of bit maps that can be used to quickly determine is the
|
||||
* peripheral identified by its PID is served by H64MX or H32MX. Then the
|
||||
* appropriate MATRIX SPSELR register can be consulted to determine if the
|
||||
* peripheral interrupts are secured or not.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SAMA5_HAVE_SAIC)
|
||||
static const uint32_t g_h64mxpids[3] =
|
||||
{
|
||||
H64MX_SPSELR0_PIDS, H64MX_SPSELR1_PIDS, H64MX_SPSELR2_PIDS
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
@ -231,44 +244,11 @@ static uint32_t *sam_spurious(int irq, uint32_t *regs)
|
||||
|
||||
static uint32_t *sam_fiqhandler(int irq, uint32_t *regs)
|
||||
{
|
||||
/* This is probably irrelevant since FIQs are not used in this
|
||||
* implementation.
|
||||
*/
|
||||
/* Dispatch the FIQ */
|
||||
|
||||
#if defined(CONFIG_DEBUG_IRQ) || defined(CONFIG_ARCH_STACKDUMP)
|
||||
lldbg("FIQ?: IRQ: %d\n");
|
||||
#endif
|
||||
PANIC();
|
||||
return regs; /* Won't get here */
|
||||
return arm_doirq(SAM_IRQ_FIQ, regs);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_aic_ish64mx
|
||||
*
|
||||
* Description:
|
||||
* Return true if the peripheral is H64 Matrix.
|
||||
*
|
||||
* Input Parameter:
|
||||
* PID = IRQ number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SAMA5_HAVE_SAIC)
|
||||
static inline bool sam_aic_ish64mx(uint32_t irq)
|
||||
{
|
||||
return (irq == SAM_IRQ_ARM ||
|
||||
irq == SAM_IRQ_XDMAC0 ||
|
||||
/* irq == SAM_IRQ_CPKCC || */
|
||||
irq == SAM_IRQ_AESB ||
|
||||
irq == SAM_IRQ_MPDDRC ||
|
||||
irq == SAM_IRQ_VDEC ||
|
||||
irq == SAM_IRQ_XDMAC1 ||
|
||||
irq == SAM_IRQ_LCDC ||
|
||||
irq == SAM_IRQ_ISI ||
|
||||
irq == SAM_IRQ_L2CC);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_aic_issecure
|
||||
*
|
||||
@ -285,7 +265,7 @@ static bool sam_aic_issecure(uint32_t irq)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
uint32_t bit;
|
||||
int regndx;
|
||||
unsigned int regndx;
|
||||
|
||||
/* Get the register index and bit mask */
|
||||
|
||||
@ -294,7 +274,8 @@ static bool sam_aic_issecure(uint32_t irq)
|
||||
|
||||
/* Get the SPSELR register address */
|
||||
|
||||
if (sam_aic_ish64mx(irq))
|
||||
DEBUGASSERT(regndx < 3);
|
||||
if ((g_h64mxpids[regndx] & bit) != 0)
|
||||
{
|
||||
/* H64MX. Use Matrix 0 */
|
||||
|
||||
@ -626,18 +607,30 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
|
||||
uint32_t *arm_decodefiq(FAR uint32_t *regs)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
/* In order to distinguish a FIQ from a true secure interrupt we need to
|
||||
* check the state of the FIQ line in the SAIC_CISR register.
|
||||
*/
|
||||
|
||||
if ((getreg32(SAM_SAIC_CISR) & AIC_CISR_NFIQ) != 0)
|
||||
{
|
||||
return arm_doirq(SAM_IRQ_FIQ, regs);
|
||||
/* Handle the FIQ */
|
||||
|
||||
ret = arm_doirq(SAM_IRQ_FIQ, regs);
|
||||
|
||||
/* Acknowledge interrupt */
|
||||
|
||||
putreg32(AIC_EOICR_ENDIT, SAM_SAIC_EOICR);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sam_decodeirq(SAM_SAIC_VBASE, regs);
|
||||
/* Handle the IRQ */
|
||||
|
||||
ret = sam_decodeirq(SAM_SAIC_VBASE, regs);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user