Need to enable FIQ in initial task state; Improve H32/64 test in IRQ handling

This commit is contained in:
Gregory Nutt 2014-06-21 09:55:09 -06:00
parent 40b7ddf68e
commit 0a134f0158
8 changed files with 130 additions and 106 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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 **************************************************************/

View File

@ -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