diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2013-12-21 15:05:48 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2013-12-21 15:05:48 -0600 |
commit | d4c848e5f49652dcb4b38506d3700d8a1e8c2dff (patch) | |
tree | 07874b7800338a66451b897bdc5fa7175d4b649e | |
parent | 61d8a57e974548c1c7ef65e9546976053f6c5a9e (diff) | |
download | px4-nuttx-d4c848e5f49652dcb4b38506d3700d8a1e8c2dff.tar.gz px4-nuttx-d4c848e5f49652dcb4b38506d3700d8a1e8c2dff.tar.bz2 px4-nuttx-d4c848e5f49652dcb4b38506d3700d8a1e8c2dff.zip |
Finishes coding of ARMv7-M high priority nested interrupt logic. Still undocumented; still not fully tested
-rw-r--r-- | nuttx/ChangeLog | 8 | ||||
-rw-r--r-- | nuttx/arch/Kconfig | 17 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-m/up_exception.S | 67 | ||||
-rw-r--r-- | nuttx/arch/arm/src/kinetis/kinetis_vectors.S | 58 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lm/lm_vectors.S | 61 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S | 58 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sam34/sam_vectors.S | 57 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_vectors.S | 60 |
8 files changed, 351 insertions, 35 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 3320f5250..0976030f3 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -6250,7 +6250,11 @@ autogenerated Documentation/NuttXConfigVariables.html file. This old configuration variable documentation is now a liability and, hence, was removed (2013-12-20). - * nuttx/arch/Kconfig, nuttx/arch/arm/Kconfig, nuttx/arch/arm/include/x/chip.h, - and nuttx/arch/arm/src/x/x_irq.c where x={kinetis, lm, lpc17xx, lpc43xx, + * arch/Kconfig, arch/arm/Kconfig, arch/arm/include/x/chip.h, and + and arch/arm/src/x/x_irq.c where x={kinetis, lm, lpc17xx, lpc43xx, sam34, or stm32}: Beginning of support for nested, high priority interrupts. Lots more still needs to be done (2013-12-21). + * arch/arm/src/armv7-m/up_exception.S and arch/arm/src/x/x_vectors.S: + where x={kinetis, lm, lpc17xx, lpc43xx, sam34, or stm32}: completes + the basic implementation of nested, high priority interreupts. + Still untested and need documentation (2013-12-21). diff --git a/nuttx/arch/Kconfig b/nuttx/arch/Kconfig index e9fc690ab..5b3fee8b7 100644 --- a/nuttx/arch/Kconfig +++ b/nuttx/arch/Kconfig @@ -281,6 +281,23 @@ config ARCH_HIPRI_INTERRUPT int up_prioritize_irq(int irq, int priority) + NOTE: ARCH_INTERRUPTSTACK must be set in kernel mode (NUTTX_KERNEL). + In kernel mode without an interrupt stack, the interrupt handler + will set the MSP to the stack pointer of the interrupted thread. If + the interrupted thread was a privileged thread, that will be the MSP + otherwise it will be the PSP. If the PSP is used, then the value of + the MSP will be invalid when the interrupt handler returns because + it will be a pointer to an old position in the unprivileged stack. + Then when the high priority interrupt occurs and uses this stale MSP, + there will most likely be a system failure. + + If the interrupt stack is selected, on the other hand, then the + interrupt handler will always set the the MSP to the interrupt + stack. So when the high priority interrupt occurs, it will either + use the MSP of the last privileged thread to run or, in the case of + the nested interrupt, the interrupt stack if no privileged task has + run + config ARCH_INT_DISABLEALL bool "Disable high priority interrupts" default y diff --git a/nuttx/arch/arm/src/armv7-m/up_exception.S b/nuttx/arch/arm/src/armv7-m/up_exception.S index a40ddf66f..3eb8f97e3 100644 --- a/nuttx/arch/arm/src/armv7-m/up_exception.S +++ b/nuttx/arch/arm/src/armv7-m/up_exception.S @@ -46,6 +46,40 @@ #include "chip.h" /************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ +/* Configuration ********************************************************************/ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* In kernel mode without an interrupt stack, this interrupt handler will set the + * MSP to the stack pointer of the interrupted thread. If the interrupted thread + * was a privileged thread, that will be the MSP otherwise it will be the PSP. If + * the PSP is used, then the value of the MSP will be invalid when the interrupt + * handler returns because it will be a pointer to an old position in the + * unprivileged stack. Then when the high priority interrupt occurs and uses this + * stale MSP, there will most likely be a system failure. + * + * If the interrupt stack is selected, on the other hand, then the interrupt + * handler will always set the the MSP to the interrupt stack. So when the high + * priority interrupt occurs, it will either use the MSP of the last privileged + * thread to run or, in the case of the nested interrupt, the interrupt stack if + * no privileged task has run. + */ + +# if defined(CONFIG_NUTTX_KERNEL) && CONFIG_ARCH_INTERRUPTSTACK < 4 +# error Interrupt stack must be used with high priority interrupts in kernel mode +# endif + + /* Use the the BASEPRI to control interrupts is required if nested, high + * priority interrupts are supported. + */ + +# ifndef CONFIG_ARMV7M_USEBASEPRI +# error CONFIG_ARMV7M_USEBASEPRI must be used with CONFIG_ARCH_HIPRI_INTERRUPT +# endif +#endif + +/************************************************************************************ * Global Symbols ************************************************************************************/ @@ -76,7 +110,7 @@ * R14 Contains the EXC_RETURN value * We are in handler mode and the current SP is the MSP * - * If CONFIG_ARCH_FPU is defined, the volatile FP registers and FPSCR are on the + * If CONFIG_ARCH_FPU is defined, the volatile FP registers and FPSCR are on the * return stack immediately above REG_XPSR. */ @@ -114,8 +148,8 @@ exception_common: * as they are restored before returning, so we can't assume that we can get at the * true values of these registers in any routine called from here. * - * XXX we could do all this saving lazily on the context switch side if we knew where to put - * the registers. + * REVISIT: we could do all this saving lazily on the context switch side if we knew + * where to put the registers. */ vstmdb r1!, {s16-s31} /* Save the non-volatile FP context */ @@ -124,23 +158,39 @@ exception_common: stmdb r1!, {r2-r11,r14} /* Save the remaining registers plus the SP/PRIMASK values */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT /* Disable interrupts, select the stack to use for interrupt handling * and call up_doirq to handle the interrupt */ cpsid i /* Disable further interrupts */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will use the stack that was current when the interrupt was taken. +#else + /* Set the BASEPRI register so that further normal interrupts will be + * masked. Nested, high priority may still occur, however. */ + mov r2, #NVIC_SYSH_DISABLE_PRIORITY + msr basepri, r2 /* Set the BASEPRI */ +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 3 + /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use + * a special special interrupt stack pointer. The way that this is done + * here prohibits nested interrupts without some additional logic! + */ + ldr sp, =g_intstackbase push {r1} /* Save the MSP on the interrupt stack */ bl up_doirq /* R0=IRQ, R1=register save area on stack */ pop {r1} /* Recover R1=main stack pointer */ + #else + /* Otherwise, we will re-use the interrupted thread's stack. That may + * mean using either MSP or PSP stack for interrupt level processing (in + * kernel mode). + */ + msr msp, r1 /* We are using the main stack pointer */ bl up_doirq /* R0=IRQ, R1=register save area on stack */ mrs r1, msp /* Recover R1=main stack pointer */ @@ -198,7 +248,7 @@ exception_common: #endif 2: - /* The EXC_RETURN value tells us whether we are returning on the MSP or PSP + /* The EXC_RETURN value tells us whether we are returning on the MSP or PSP */ #ifdef CONFIG_NUTTX_KERNEL @@ -230,7 +280,10 @@ exception_common: #ifdef CONFIG_ARMV7M_USEBASEPRI msr basepri, r3 /* Restore interrupts priority masking */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsie i /* Re-enable interrupts */ +#endif + #else msr primask, r3 /* Restore interrupts */ #endif diff --git a/nuttx/arch/arm/src/kinetis/kinetis_vectors.S b/nuttx/arch/arm/src/kinetis/kinetis_vectors.S index 7508d077a..5bf9ce3ba 100644 --- a/nuttx/arch/arm/src/kinetis/kinetis_vectors.S +++ b/nuttx/arch/arm/src/kinetis/kinetis_vectors.S @@ -47,8 +47,37 @@ /************************************************************************************************ * Preprocessor Definitions ************************************************************************************************/ -/* Memory Map: - * +/* Configuration ********************************************************************************/ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* In kernel mode without an interrupt stack, this interrupt handler will set the MSP to the + * stack pointer of the interrupted thread. If the interrupted thread was a privileged + * thread, that will be the MSP otherwise it will be the PSP. If the PSP is used, then the + * value of the MSP will be invalid when the interrupt handler returns because it will be a + * pointer to an old position in the unprivileged stack. Then when the high priority + * interrupt occurs and uses this stale MSP, there will most likely be a system failure. + * + * If the interrupt stack is selected, on the other hand, then the interrupt handler will + * always set the the MSP to the interrupt stack. So when the high priority interrupt occurs, + * it will either use the MSP of the last privileged thread to run or, in the case of the + * nested interrupt, the interrupt stack if no privileged task has run. + */ + +# if defined(CONFIG_NUTTX_KERNEL) && CONFIG_ARCH_INTERRUPTSTACK < 4 +# error Interrupt stack must be used with high priority interrupts in kernel mode +# endif + + /* Use the the BASEPRI to control interrupts is required if nested, high + * priority interrupts are supported. + */ + +# ifndef CONFIG_ARMV7M_USEBASEPRI +# error CONFIG_ARMV7M_USEBASEPRI must be used with CONFIG_ARCH_HIPRI_INTERRUPT +# endif +#endif + +/* Memory Map ***********************************************************************************/ +/* * 0x0000:0000 - Beginning of FLASH. Address of vectors * 0x1800:0000 - Start of CPU SRAM and start of .data (_sdata) * - End of .data (_edata) and start of .bss (_sbss) @@ -637,23 +666,39 @@ kinetis_common: stmdb r1!, {r2-r11} /* Save the remaining registers plus the SP value */ #endif +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT /* Disable interrupts, select the stack to use for interrupt handling * and call up_doirq to handle the interrupt */ cpsid i /* Disable further interrupts */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will re-use the main stack for interrupt level processing. +#else + /* Set the BASEPRI register so that further normal interrupts will be + * masked. Nested, high priority may still occur, however. */ + mov r2, #NVIC_SYSH_DISABLE_PRIORITY + msr basepri, r2 /* Set the BASEPRI */ +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 3 + /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use + * a special special interrupt stack pointer. The way that this is done + * here prohibits nested interrupts without some additional logic! + */ + ldr sp, =g_intstackbase str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */ + #else + /* Otherwise, we will re-use the interrupted thread's stack. That may + * mean using either MSP or PSP stack for interrupt level processing (in + * kernel mode). + */ + mov sp, r1 /* We are using the main stack pointer */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, sp /* Recover R1=main stack pointer */ @@ -766,7 +811,10 @@ kinetis_common: #ifdef CONFIG_ARMV7M_USEBASEPRI msr basepri, r3 /* Restore interrupts priority masking */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsie i /* Re-enable interrupts */ +#endif + #else msr primask, r3 /* Restore interrupts */ #endif diff --git a/nuttx/arch/arm/src/lm/lm_vectors.S b/nuttx/arch/arm/src/lm/lm_vectors.S index e48f8833b..6635fa906 100644 --- a/nuttx/arch/arm/src/lm/lm_vectors.S +++ b/nuttx/arch/arm/src/lm/lm_vectors.S @@ -2,7 +2,7 @@ * arch/arm/src/lm/lm_vectors.S * arch/arm/src/chip/lm_vectors.S * - * Copyright (C) 2009-2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2009-2010, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -52,9 +52,39 @@ /************************************************************************************ * Preprocessor Definitions ************************************************************************************/ +/* Configuration ********************************************************************/ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* In kernel mode without an interrupt stack, this interrupt handler will set the + * MSP to the stack pointer of the interrupted thread. If the interrupted thread + * was a privileged thread, that will be the MSP otherwise it will be the PSP. If + * the PSP is used, then the value of the MSP will be invalid when the interrupt + * handler returns because it will be a pointer to an old position in the + * unprivileged stack. Then when the high priority interrupt occurs and uses this + * stale MSP, there will most likely be a system failure. + * + * If the interrupt stack is selected, on the other hand, then the interrupt + * handler will always set the the MSP to the interrupt stack. So when the high + * priority interrupt occurs, it will either use the MSP of the last privileged + * thread to run or, in the case of the nested interrupt, the interrupt stack if + * no privileged task has run. + */ + +# if defined(CONFIG_NUTTX_KERNEL) && CONFIG_ARCH_INTERRUPTSTACK < 4 +# error Interrupt stack must be used with high priority interrupts in kernel mode +# endif + + /* Use the the BASEPRI to control interrupts is required if nested, high + * priority interrupts are supported. + */ + +# ifndef CONFIG_ARMV7M_USEBASEPRI +# error CONFIG_ARMV7M_USEBASEPRI must be used with CONFIG_ARCH_HIPRI_INTERRUPT +# endif +#endif -/* Memory Map: - * +/* Memory Map ***********************************************************************/ +/* * 0x0000:0000 - Beginning of FLASH. Address of vectors (if not using bootloader) * 0x0002:0000 - Address of vectors if using bootloader * 0x0003:ffff - End of flash @@ -240,23 +270,39 @@ lm_irqcommon: stmdb r1!, {r2-r11} /* Save the remaining registers plus the SP value */ #endif +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT /* Disable interrupts, select the stack to use for interrupt handling * and call up_doirq to handle the interrupt */ cpsid i /* Disable further interrupts */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will re-use the main stack for interrupt level processing. +#else + /* Set the BASEPRI register so that further normal interrupts will be + * masked. Nested, high priority may still occur, however. */ + mov r2, #NVIC_SYSH_DISABLE_PRIORITY + msr basepri, r2 /* Set the BASEPRI */ +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 3 + /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use + * a special special interrupt stack pointer. The way that this is done + * here prohibits nested interrupts without some additional logic! + */ + ldr sp, =g_intstackbase str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */ + #else + /* Otherwise, we will re-use the interrupted thread's stack. That may + * mean using either MSP or PSP stack for interrupt level processing (in + * kernel mode). + */ + mov sp, r1 /* We are using the main stack pointer */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, sp /* Recover R1=main stack pointer */ @@ -369,7 +415,10 @@ lm_irqcommon: #ifdef CONFIG_ARMV7M_USEBASEPRI msr basepri, r3 /* Restore interrupts priority masking */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsie i /* Re-enable interrupts */ +#endif + #else msr primask, r3 /* Restore interrupts */ #endif diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S b/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S index c0b79b048..beb44d5e6 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S @@ -48,8 +48,37 @@ /************************************************************************************************ * Preprocessor Definitions ************************************************************************************************/ -/* Memory Map: - * +/* Configuration ********************************************************************************/ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* In kernel mode without an interrupt stack, this interrupt handler will set the MSP to the + * stack pointer of the interrupted thread. If the interrupted thread was a privileged + * thread, that will be the MSP otherwise it will be the PSP. If the PSP is used, then the + * value of the MSP will be invalid when the interrupt handler returns because it will be a + * pointer to an old position in the unprivileged stack. Then when the high priority + * interrupt occurs and uses this stale MSP, there will most likely be a system failure. + * + * If the interrupt stack is selected, on the other hand, then the interrupt handler will + * always set the the MSP to the interrupt stack. So when the high priority interrupt occurs, + * it will either use the MSP of the last privileged thread to run or, in the case of the + * nested interrupt, the interrupt stack if no privileged task has run. + */ + +# if defined(CONFIG_NUTTX_KERNEL) && CONFIG_ARCH_INTERRUPTSTACK < 4 +# error Interrupt stack must be used with high priority interrupts in kernel mode +# endif + + /* Use the the BASEPRI to control interrupts is required if nested, high + * priority interrupts are supported. + */ + +# ifndef CONFIG_ARMV7M_USEBASEPRI +# error CONFIG_ARMV7M_USEBASEPRI must be used with CONFIG_ARCH_HIPRI_INTERRUPT +# endif +#endif + +/* Memory Map ***********************************************************************************/ +/* * 0x0000:0000 - Beginning of FLASH. Address of vectors * 0x0003:ffff - End of flash * 0x1000:0000 - Start of CPU SRAM and start of .data (_sdata) @@ -249,23 +278,39 @@ lpc17_common: stmdb r1!, {r2-r11} /* Save the remaining registers plus the SP value */ #endif +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT /* Disable interrupts, select the stack to use for interrupt handling * and call up_doirq to handle the interrupt */ cpsid i /* Disable further interrupts */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will re-use the main stack for interrupt level processing. +#else + /* Set the BASEPRI register so that further normal interrupts will be + * masked. Nested, high priority may still occur, however. */ + mov r2, #NVIC_SYSH_DISABLE_PRIORITY + msr basepri, r2 /* Set the BASEPRI */ +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 3 + /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use + * a special special interrupt stack pointer. The way that this is done + * here prohibits nested interrupts without some additional logic! + */ + ldr sp, =g_intstackbase str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */ + #else + /* Otherwise, we will re-use the interrupted thread's stack. That may + * mean using either MSP or PSP stack for interrupt level processing (in + * kernel mode). + */ + mov sp, r1 /* We are using the main stack pointer */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, sp /* Recover R1=main stack pointer */ @@ -378,7 +423,10 @@ lpc17_common: #ifdef CONFIG_ARMV7M_USEBASEPRI msr basepri, r3 /* Restore interrupts priority masking */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsie i /* Re-enable interrupts */ +#endif + #else msr primask, r3 /* Restore interrupts */ #endif diff --git a/nuttx/arch/arm/src/sam34/sam_vectors.S b/nuttx/arch/arm/src/sam34/sam_vectors.S index 490a81a7a..97e144388 100644 --- a/nuttx/arch/arm/src/sam34/sam_vectors.S +++ b/nuttx/arch/arm/src/sam34/sam_vectors.S @@ -46,9 +46,37 @@ /************************************************************************************************ * Preprocessor Definitions ************************************************************************************************/ +/* Configuration ********************************************************************************/ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* In kernel mode without an interrupt stack, this interrupt handler will set the MSP to the + * stack pointer of the interrupted thread. If the interrupted thread was a privileged + * thread, that will be the MSP otherwise it will be the PSP. If the PSP is used, then the + * value of the MSP will be invalid when the interrupt handler returns because it will be a + * pointer to an old position in the unprivileged stack. Then when the high priority + * interrupt occurs and uses this stale MSP, there will most likely be a system failure. + * + * If the interrupt stack is selected, on the other hand, then the interrupt handler will + * always set the the MSP to the interrupt stack. So when the high priority interrupt occurs, + * it will either use the MSP of the last privileged thread to run or, in the case of the + * nested interrupt, the interrupt stack if no privileged task has run. + */ + +# if defined(CONFIG_NUTTX_KERNEL) && CONFIG_ARCH_INTERRUPTSTACK < 4 +# error Interrupt stack must be used with high priority interrupts in kernel mode +# endif + + /* Use the the BASEPRI to control interrupts is required if nested, high + * priority interrupts are supported. + */ + +# ifndef CONFIG_ARMV7M_USEBASEPRI +# error CONFIG_ARMV7M_USEBASEPRI must be used with CONFIG_ARCH_HIPRI_INTERRUPT +# endif +#endif -/* Memory Map: - * +/* Memory Map ***********************************************************************************/ +/* * 0x0800:0000 - Beginning of FLASH. Address of vectors. Mapped to address 0x0000:0000 at boot * time. * 0x0803:ffff - End of flash @@ -255,23 +283,39 @@ sam_common: stmdb r1!, {r2-r11} /* Save the remaining registers plus the SP value */ #endif +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT /* Disable interrupts, select the stack to use for interrupt handling * and call up_doirq to handle the interrupt */ cpsid i /* Disable further interrupts */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will re-use the main stack for interrupt level processing. +#else + /* Set the BASEPRI register so that further normal interrupts will be + * masked. Nested, high priority may still occur, however. */ + mov r2, #NVIC_SYSH_DISABLE_PRIORITY + msr basepri, r2 /* Set the BASEPRI */ +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 3 + /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use + * a special special interrupt stack pointer. The way that this is done + * here prohibits nested interrupts without some additional logic! + */ + ldr sp, =g_intstackbase str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */ + #else + /* Otherwise, we will re-use the interrupted thread's stack. That may + * mean using either MSP or PSP stack for interrupt level processing (in + * kernel mode). + */ + mov sp, r1 /* We are using the main stack pointer */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, sp /* Recover R1=main stack pointer */ @@ -384,7 +428,10 @@ sam_common: #ifdef CONFIG_ARMV7M_USEBASEPRI msr basepri, r3 /* Restore interrupts priority masking */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsie i /* Re-enable interrupts */ +#endif + #else msr primask, r3 /* Restore interrupts */ #endif diff --git a/nuttx/arch/arm/src/stm32/stm32_vectors.S b/nuttx/arch/arm/src/stm32/stm32_vectors.S index d16192f71..e6e6d31dd 100644 --- a/nuttx/arch/arm/src/stm32/stm32_vectors.S +++ b/nuttx/arch/arm/src/stm32/stm32_vectors.S @@ -52,8 +52,39 @@ /************************************************************************************ * Preprocessor Definitions ************************************************************************************/ -/* Memory Map: - * +/* Configuration ********************************************************************/ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* In kernel mode without an interrupt stack, this interrupt handler will set the + * MSP to the stack pointer of the interrupted thread. If the interrupted thread + * was a privileged thread, that will be the MSP otherwise it will be the PSP. If + * the PSP is used, then the value of the MSP will be invalid when the interrupt + * handler returns because it will be a pointer to an old position in the + * unprivileged stack. Then when the high priority interrupt occurs and uses this + * stale MSP, there will most likely be a system failure. + * + * If the interrupt stack is selected, on the other hand, then the interrupt + * handler will always set the the MSP to the interrupt stack. So when the high + * priority interrupt occurs, it will either use the MSP of the last privileged + * thread to run or, in the case of the nested interrupt, the interrupt stack if + * no privileged task has run. + */ + +# if defined(CONFIG_NUTTX_KERNEL) && CONFIG_ARCH_INTERRUPTSTACK < 4 +# error Interrupt stack must be used with high priority interrupts in kernel mode +# endif + + /* Use the the BASEPRI to control interrupts is required if nested, high + * priority interrupts are supported. + */ + +# ifndef CONFIG_ARMV7M_USEBASEPRI +# error CONFIG_ARMV7M_USEBASEPRI must be used with CONFIG_ARCH_HIPRI_INTERRUPT +# endif +#endif + +/* Memory Map ***********************************************************************/ +/* * 0x0800:0000 - Beginning of FLASH. Address of vectors (if not using bootloader) * Mapped to address 0x0000:0000 at boot time. * 0x0800:3000 - Address of vectors if using bootloader @@ -262,23 +293,39 @@ stm32_common: stmdb r1!, {r2-r11} /* Save the remaining registers plus the SP value */ #endif +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT /* Disable interrupts, select the stack to use for interrupt handling * and call up_doirq to handle the interrupt */ cpsid i /* Disable further interrupts */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will re-use the main stack for interrupt level processing. +#else + /* Set the BASEPRI register so that further normal interrupts will be + * masked. Nested, high priority may still occur, however. */ + mov r2, #NVIC_SYSH_DISABLE_PRIORITY + msr basepri, r2 /* Set the BASEPRI */ +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 3 + /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use + * a special special interrupt stack pointer. The way that this is done + * here prohibits nested interrupts without some additional logic! + */ + ldr sp, =g_intstackbase str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */ + #else + /* Otherwise, we will re-use the interrupted thread's stack. That may + * mean using either MSP or PSP stack for interrupt level processing (in + * kernel mode). + */ + mov sp, r1 /* We are using the main stack pointer */ bl up_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, sp /* Recover R1=main stack pointer */ @@ -391,7 +438,10 @@ stm32_common: #ifdef CONFIG_ARMV7M_USEBASEPRI msr basepri, r3 /* Restore interrupts priority masking */ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsie i /* Re-enable interrupts */ +#endif + #else msr primask, r3 /* Restore interrupts */ #endif |