Fix major misthink in Cortex-M0 port: The Cortex-M0 has no BASEPRI register. We have to revert to using the nasty PRIMASK register

This commit is contained in:
Gregory Nutt 2013-04-16 18:00:59 -06:00
parent 9da8869efc
commit a8004f9e07
15 changed files with 105 additions and 122 deletions

View File

@ -71,7 +71,7 @@
*/
#define REG_R13 (0) /* R13 = SP at time of interrupt */
#define REG_BASEPRI (1) /* BASEPRI */
#define REG_PRIMASK (1) /* PRIMASK */
#define REG_R4 (2) /* R4 */
#define REG_R5 (3) /* R5 */
#define REG_R6 (4) /* R6 */
@ -176,7 +176,7 @@ struct xcptcontext
*/
uint32_t saved_pc;
uint32_t saved_basepri;
uint32_t saved_primask;
uint32_t saved_xpsr;
# ifdef CONFIG_NUTTX_KERNEL
@ -237,44 +237,12 @@ static inline void setprimask(uint32_t primask)
: "memory");
}
/* Get/set the BASEPRI register. The BASEPRI register defines the minimum
* priority for exception processing. When BASEPRI is set to a nonzero
* value, it prevents the activation of all exceptions with the same or
* lower priority level as the BASEPRI value.
*/
static inline uint8_t getbasepri(void) inline_function;
static inline uint8_t getbasepri(void)
{
uint32_t basepri;
__asm__ __volatile__
(
"\tmrs %0, basepri\n"
: "=r" (basepri)
:
: "memory");
return (uint8_t)basepri;
}
static inline void setbasepri(uint32_t basepri) inline_function;
static inline void setbasepri(uint32_t basepri)
{
__asm__ __volatile__
(
"\tmsr basepri, %0\n"
:
: "r" (basepri)
: "memory");
}
/* Disable IRQs */
static inline void irqdisable(void) inline_function;
static inline void irqdisable(void)
{
setbasepri(NVIC_SYSH_DISABLE_PRIORITY);
__asm__ __volatile__ ("\tcpsid i\n");
}
/* Save the current primask state & disable IRQs */
@ -282,9 +250,21 @@ static inline void irqdisable(void)
static inline irqstate_t irqsave(void) inline_function;
static inline irqstate_t irqsave(void)
{
uint8_t basepri = getbasepri();
setbasepri(NVIC_SYSH_DISABLE_PRIORITY);
return (irqstate_t)basepri;
unsigned short primask;
/* Return the current value of primask register and set
* bit 0 of the primask register to disable interrupts
*/
__asm__ __volatile__
(
"\tmrs %0, primask\n"
"\tcpsid i\n"
: "=r" (primask)
:
: "memory");
return primask;
}
/* Enable IRQs */
@ -292,7 +272,6 @@ static inline irqstate_t irqsave(void)
static inline void irqenable(void) inline_function;
static inline void irqenable(void)
{
setbasepri(0);
__asm__ __volatile__ ("\tcpsie i\n");
}
@ -301,7 +280,16 @@ static inline void irqenable(void)
static inline void irqrestore(irqstate_t flags) inline_function;
static inline void irqrestore(irqstate_t flags)
{
setbasepri((uint32_t)flags);
/* If bit 0 of the primask is 0, then we need to restore
* interrupts.
*/
__asm__ __volatile__
(
"\tmsr primask, %0\n"
:
: "r" (flags)
: "memory");
}
/* Get/set IPSR */

View File

@ -293,7 +293,7 @@ static inline void irqrestore(irqstate_t flags)
setbasepri((uint32_t)flags);
#else
/* If bit 0 of the primask is 0, then we need to restore
* interupts.
* interrupts.
*/
__asm__ __volatile__

View File

@ -103,9 +103,6 @@
#define NVIC_SYSH_PRIORITY_MAX 0x00 /* Zero is maximum priority */
#define NVIC_SYSH_PRIORITY_STEP 0x40 /* Steps between supported priority values */
#define NVIC_SYSH_DISABLE_PRIORITY (NVIC_SYSH_PRIORITY_MAX + NVIC_SYSH_PRIORITY_STEP)
#define NVIC_SYSH_SVCALL_PRIORITY NVIC_SYSH_PRIORITY_MAX
/************************************************************************************
* Public Types
************************************************************************************/

View File

@ -646,9 +646,6 @@
#define NVIC_SYSH_PRIORITY_MAX 0x00 /* Zero is maximum priority */
#define NVIC_SYSH_PRIORITY_STEP 0x40 /* Five bits of interrupt priority used */
#define NVIC_SYSH_DISABLE_PRIORITY (NVIC_SYSH_PRIORITY_MAX + NVIC_SYSH_PRIORITY_STEP)
#define NVIC_SYSH_SVCALL_PRIORITY NVIC_SYSH_PRIORITY_MAX
/************************************************************************************
* Public Types
************************************************************************************/

View File

@ -148,12 +148,12 @@ static inline void up_registerdump(void)
current_regs[REG_R12], current_regs[REG_R13],
current_regs[REG_R14], current_regs[REG_R15]);
#ifdef CONFIG_NUTTX_KERNEL
lldbg("xPSR: %08x BASEPRI: %08x EXEC_RETURN: %08x\n",
current_regs[REG_XPSR], current_regs[REG_BASEPRI],
lldbg("xPSR: %08x PRIMASK: %08x EXEC_RETURN: %08x\n",
current_regs[REG_XPSR], current_regs[REG_PRIMASK],
current_regs[REG_EXC_RETURN]);
#else
lldbg("xPSR: %08x BASEPRI: %08x\n",
current_regs[REG_XPSR], current_regs[REG_BASEPRI]);
lldbg("xPSR: %08x PRIMASK: %08x\n",
current_regs[REG_XPSR], current_regs[REG_PRIMASK]);
#endif
}
}

View File

@ -113,15 +113,15 @@ exception_common:
*/
2:
/* Save SP, BASEPRI, and R4-R7 in the context array */
/* Save SP, PRIMASK, and R4-R7 in the context array */
sub r1, #SW_XCPT_SIZE /* R1=Beginning of context array on the stack */
mov r2, #XCPTCONTEXT_SIZE /* R2=Size of the context array */
add r2, r1 /* R2=MSP/PSP before the interrupt was taken */
/* (ignoring the xPSR[9] alignment bit) */
mrs r3, basepri /* R3=Current BASEPRI setting */
mrs r3, primask /* R3=Current PRIMASK setting */
mov r0, r1 /* Copy the context array pointer */
stmia r0!, {r2-r7} /* Save the SP, BASEPRI, and R4-R7 in the context array */
stmia r0!, {r2-r7} /* Save the SP, PRIMASK, and R4-R7 in the context array */
/* Save R8-R11 and the EXEC_RETURN value in the context array */
@ -215,7 +215,7 @@ exception_common:
mov r11, r5
#endif
/* Recover SP (R2), BASEPRI (R3), and R4-R7. Determine the value of
/* Recover SP (R2), PRIMASK (R3), and R4-R7. Determine the value of
* the stack pointer as it was on entry to the exception handler.
*/
@ -246,7 +246,7 @@ exception_common:
/* Restore the interrupt state */
msr basepri, r3 /* Restore interrupts priority masking*/
msr primask, r3 /* Restore interrupts priority masking*/
cpsie i /* Re-enable interrupts */
/* Always return with R14 containing the special value that will: (1)

View File

@ -90,23 +90,68 @@
int up_hardfault(int irq, FAR void *context)
{
#if defined(CONFIG_DEBUG_HARDFAULT)
#if defined(CONFIG_DEBUG_HARDFAULT) || !defined(CONFIG_ARMV7M_USEBASEPRI)
uint32_t *regs = (uint32_t*)context;
#endif
/* Get the value of the program counter where the fault occurred */
#ifndef CONFIG_ARMV7M_USEBASEPRI
uint16_t *pc = (uint16_t*)regs[REG_PC] - 1;
/* Check if the pc lies in known FLASH memory.
* REVISIT: What if the PC lies in "unknown" external memory? Best
* use the BASEPRI register if you have external memory.
*/
#ifdef CONFIG_NUTTX_KERNEL
/* In the kernel build, SVCalls are expected in either the base, kernel
* FLASH region or in the user FLASH region.
*/
if (((uintptr_t)pc >= (uintptr_t)&_stext &&
(uintptr_t)pc < (uintptr_t)&_etext) ||
((uintptr_t)pc >= (uintptr_t)USERSPACE->us_textstart &&
(uintptr_t)pc < (uintptr_t)USERSPACE->us_textend))
#else
/* SVCalls are expected only from the base, kernel FLASH region */
if ((uintptr_t)pc >= (uintptr_t)&_stext &&
(uintptr_t)pc < (uintptr_t)&_etext)
#endif
{
/* Fetch the instruction that caused the Hard fault */
uint16_t insn = *pc;
hfdbg(" PC: %p INSN: %04x\n", pc, insn);
/* If this was the instruction 'svc 0', then forward processing
* to the SVCall handler
*/
if (insn == INSN_SVC0)
{
hfdbg("Forward SVCall\n");
return up_svcall(irq, context);
}
}
#endif
#if defined(CONFIG_DEBUG_HARDFAULT)
/* Dump some hard fault info */
hfdbg("\nHard Fault:\n");
hfdbg(" IRQ: %d regs: %p\n", irq, regs);
hfdbg(" BASEPRI: %08x PRIMASK: %08x IPSR: %08x\n",
getbasepri(), getprimask(), getipsr());
hfdbg(" PRIMASK: %08x IPSR: %08x\n",
getprimask(), getipsr());
hfdbg(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n",
regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],
regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]);
hfdbg(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n",
regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11],
regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]);
hfdbg(" xPSR: %08x BASEPRI: %08x (saved)\n",
current_regs[REG_XPSR], current_regs[REG_BASEPRI]);
hfdbg(" xPSR: %08x PRIMASK: %08x (saved)\n",
current_regs[REG_XPSR], current_regs[REG_PRIMASK]);
#endif
(void)irqsave();

View File

@ -139,6 +139,6 @@ void up_initial_state(struct tcb_s *tcb)
/* Enable or disable interrupts, based on user configuration */
#ifdef CONFIG_SUPPRESS_INTERRUPTS
xcp->regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
xcp->regs[REG_PRIMASK] = 1;
#endif /* CONFIG_SUPPRESS_INTERRUPTS */
}

View File

@ -156,7 +156,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.sigdeliver = sigdeliver;
tcb->xcp.saved_pc = current_regs[REG_PC];
tcb->xcp.saved_basepri = current_regs[REG_BASEPRI];
tcb->xcp.saved_primask = current_regs[REG_PRIMASK];
tcb->xcp.saved_xpsr = current_regs[REG_XPSR];
/* Then set up to vector to the trampoline with interrupts
@ -165,7 +165,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/
current_regs[REG_PC] = (uint32_t)up_sigdeliver;
current_regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
current_regs[REG_PRIMASK] = 1;
current_regs[REG_XPSR] = ARMV6M_XPSR_T;
#ifdef CONFIG_NUTTX_KERNEL
current_regs[REG_XPSR] = EXC_RETURN_PRIVTHR;
@ -194,7 +194,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.sigdeliver = sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR];
/* Then set up to vector to the trampoline with interrupts
@ -203,7 +203,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_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
tcb->xcp.regs[REG_PRIMASK] = 1;
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
}

View File

@ -107,7 +107,7 @@ void up_sigdeliver(void)
up_copystate(regs, rtcb->xcp.regs);
regs[REG_PC] = rtcb->xcp.saved_pc;
regs[REG_BASEPRI] = rtcb->xcp.saved_basepri;
regs[REG_PRIMASK] = rtcb->xcp.saved_primask;
regs[REG_XPSR] = rtcb->xcp.saved_xpsr;
/* Get a local copy of the sigdeliver function pointer. We do this so that
@ -120,7 +120,7 @@ void up_sigdeliver(void)
/* Then restore the task interrupt state */
irqrestore((uint8_t)regs[REG_BASEPRI]);
irqrestore((uint8_t)regs[REG_PRIMASK]);
/* Deliver the signal */

View File

@ -183,11 +183,11 @@ int up_svcall(int irq, FAR void *context)
regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11],
regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]);
# ifdef CONFIG_NUTTX_KERNEL
svcdbg(" PSR: %08x BASEPRI: %08x EXC_RETURN: %08x\n",
regs[REG_XPSR], regs[REG_BASEPRI], regs[REG_EXC_RETURN]);
svcdbg(" PSR: %08x PRIMASK: %08x EXC_RETURN: %08x\n",
regs[REG_XPSR], regs[REG_PRIMASK], regs[REG_EXC_RETURN]);
# else
svcdbg(" PSR: %08x BASEPRI: %08x\n",
regs[REG_XPSR], regs[REG_BASEPRI]);
svcdbg(" PSR: %08x PRIMASK: %08x\n",
regs[REG_XPSR], regs[REG_PRIMASK]);
# endif
}
#endif
@ -495,12 +495,12 @@ int up_svcall(int irq, FAR void *context)
current_regs[REG_R8], current_regs[REG_R9], current_regs[REG_R10], current_regs[REG_R11],
current_regs[REG_R12], current_regs[REG_R13], current_regs[REG_R14], current_regs[REG_R15]);
#ifdef CONFIG_NUTTX_KERNEL
svcdbg(" PSR: %08x BASEPRI: %08x EXC_RETURN: %08x\n",
current_regs[REG_XPSR], current_regs[REG_BASEPRI],
svcdbg(" PSR: %08x PRIMASK: %08x EXC_RETURN: %08x\n",
current_regs[REG_XPSR], current_regs[REG_PRIMASK],
current_regs[REG_EXC_RETURN]);
#else
svcdbg(" PSR: %08x BASEPRI: %08x\n",
current_regs[REG_XPSR], current_regs[REG_BASEPRI]);
svcdbg(" PSR: %08x PRIMASK: %08x\n",
current_regs[REG_XPSR], current_regs[REG_PRIMASK]);
#endif
}
# ifdef CONFIG_DEBUG_SVCALL

View File

@ -46,7 +46,7 @@
#include <arch/kl/chip.h>
/* Define the number of interrupt vectors that needed to be support for this chip */
/* Define the number of interrupt vectors that need to be supported for this chip */
#define ARMV6M_PERIPHERAL_INTERRUPTS 32

View File

@ -159,27 +159,6 @@ static int kl_reserved(int irq, FAR void *context)
}
#endif
/****************************************************************************
* Name: kl_prioritize_syscall
*
* Description:
* Set the priority of an exception. This function may be needed
* internally even if support for prioritized interrupts is not enabled.
*
****************************************************************************/
static inline void kl_prioritize_syscall(int priority)
{
uint32_t regval;
/* SVCALL is system handler 11 */
regval = getreg32(ARMV6M_SYSCON_SHPR2);
regval &= ~SYSCON_SHPR2_PRI_11_MASK;
regval |= (priority << SYSCON_SHPR2_PRI_11_SHIFT);
putreg32(regval, ARMV6M_SYSCON_SHPR2);
}
/****************************************************************************
* Name: kl_clrpend
*
@ -256,7 +235,6 @@ void up_irqinitialize(void)
#ifdef CONFIG_ARCH_IRQPRIO
/* up_prioritize_irq(KL_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN); */
#endif
kl_prioritize_syscall(NVIC_SYSH_SVCALL_PRIORITY);
/* Attach all other processor exceptions (except reset and sys tick) */

View File

@ -46,7 +46,7 @@
#include <arch/nuc1xx/chip.h>
/* Define the number of interrupt vectors that needed to be support for this chip */
/* Define the number of interrupt vectors that need to be supported for this chip */
#define ARMV6M_PERIPHERAL_INTERRUPTS 32

View File

@ -159,27 +159,6 @@ static int nuc_reserved(int irq, FAR void *context)
}
#endif
/****************************************************************************
* Name: nuc_prioritize_syscall
*
* Description:
* Set the priority of an exception. This function may be needed
* internally even if support for prioritized interrupts is not enabled.
*
****************************************************************************/
static inline void nuc_prioritize_syscall(int priority)
{
uint32_t regval;
/* SVCALL is system handler 11 */
regval = getreg32(ARMV6M_SYSCON_SHPR2);
regval &= ~SYSCON_SHPR2_PRI_11_MASK;
regval |= (priority << SYSCON_SHPR2_PRI_11_SHIFT);
putreg32(regval, ARMV6M_SYSCON_SHPR2);
}
/****************************************************************************
* Name: nuc_clrpend
*
@ -256,7 +235,6 @@ void up_irqinitialize(void)
#ifdef CONFIG_ARCH_IRQPRIO
/* up_prioritize_irq(NUC_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN); */
#endif
nuc_prioritize_syscall(NVIC_SYSH_SVCALL_PRIORITY);
/* Attach all other processor exceptions (except reset and sys tick) */