From c97d11aa7bbd3a92061eb710125050c1e291e251 Mon Sep 17 00:00:00 2001 From: Abdelatif Guettouche Date: Mon, 12 Oct 2020 12:49:58 +0100 Subject: [PATCH] arch/xtensa: Add the optional interrupt stack. Signed-off-by: Abdelatif Guettouche --- arch/Kconfig | 1 + arch/xtensa/src/common/xtensa.h | 27 +++++----- arch/xtensa/src/common/xtensa_checkstack.c | 6 +-- arch/xtensa/src/common/xtensa_dumpstate.c | 11 ++--- arch/xtensa/src/common/xtensa_initialize.c | 32 ++++++++++++ arch/xtensa/src/common/xtensa_int_handlers.S | 52 +++++++++++++++++--- arch/xtensa/src/esp32/esp32_irq.c | 6 --- 7 files changed, 97 insertions(+), 38 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index deb4aac98f..a7a32e66e9 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -92,6 +92,7 @@ config ARCH_X86_64 config ARCH_XTENSA bool "Xtensa" + select ARCH_HAVE_INTERRUPTSTACK select ARCH_HAVE_STACKCHECK select ARCH_HAVE_CUSTOMOPT select ARCH_HAVE_TESTSET diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index 8e91029707..7d3d86c233 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -85,18 +85,10 @@ /* Check if an interrupt stack size is configured */ -#define HAVE_INTERRUPTSTACK 1 - -#if !defined(CONFIG_ARCH_INTERRUPTSTACK) +#ifndef CONFIG_ARCH_INTERRUPTSTACK # define CONFIG_ARCH_INTERRUPTSTACK 0 -# undef HAVE_INTERRUPTSTACK -#elif CONFIG_ARCH_INTERRUPTSTACK < 16 -# warning CONFIG_ARCH_INTERRUPTSTACK is to small -# undef HAVE_INTERRUPTSTACK #endif -#define INTERRUPTSTACK_SIZE ((CONFIG_ARCH_INTERRUPTSTACK + 15) & ~15) -#define INTERRUPT_STACKWORDS (INTERRUPTSTACK_SIZE >> 2) /* An IDLE thread stack size for CPU0 must be defined */ @@ -109,10 +101,6 @@ #define IDLETHREAD_STACKSIZE ((CONFIG_IDLETHREAD_STACKSIZE + 15) & ~15) #define IDLETHREAD_STACKWORDS (IDLETHREAD_STACKSIZE >> 2) -/* Used for stack usage measurements */ - -#define STACK_COLOR 0xdeadbeef - /* In the XTENSA model, the state is copied from the stack to the TCB, but * only a referenced is passed to get the state from the TCB. * @@ -150,6 +138,14 @@ #define getreg32(a) (*(volatile uint32_t *)(a)) #define putreg32(v,a) (*(volatile uint32_t *)(a) = (v)) +/* This is the value used to mark the stack for subsequent stack monitoring + * logic. + */ + +#define STACK_COLOR 0xdeadbeef +#define INTSTACK_COLOR 0xdeadbeef +#define HEAP_COLOR 'h' + /**************************************************************************** * Public Types ****************************************************************************/ @@ -181,10 +177,11 @@ extern volatile uint32_t *g_current_regs[1]; #endif -#ifdef HAVE_INTERRUPTSTACK +#if CONFIG_ARCH_INTERRUPTSTACK > 15 /* The (optional) interrupt stack */ -extern uint32_t g_intstack[INTERRUPT_STACKWORDS]; +extern uint32_t g_intstackalloc; /* Allocated interrupt stack */ +extern uint32_t g_intstackbase; /* Initial top of interrupt stack */ #endif /* Address of the CPU0 IDLE thread */ diff --git a/arch/xtensa/src/common/xtensa_checkstack.c b/arch/xtensa/src/common/xtensa_checkstack.c index 8a177cc3a6..cfd08a8d09 100644 --- a/arch/xtensa/src/common/xtensa_checkstack.c +++ b/arch/xtensa/src/common/xtensa_checkstack.c @@ -197,16 +197,16 @@ ssize_t up_check_stack_remain(void) return up_check_tcbstack_remain(this_task()); } -#if CONFIG_ARCH_INTERRUPTSTACK > 3 +#if CONFIG_ARCH_INTERRUPTSTACK > 15 size_t up_check_intstack(void) { return do_stackcheck((uintptr_t)&g_intstackalloc, - (CONFIG_ARCH_INTERRUPTSTACK & ~3)); + (CONFIG_ARCH_INTERRUPTSTACK & ~15)); } size_t up_check_intstack_remain(void) { - return (CONFIG_ARCH_INTERRUPTSTACK & ~3) - up_check_intstack(); + return (CONFIG_ARCH_INTERRUPTSTACK & ~15) - up_check_intstack(); } #endif diff --git a/arch/xtensa/src/common/xtensa_dumpstate.c b/arch/xtensa/src/common/xtensa_dumpstate.c index 04109a072e..cf35f15dec 100644 --- a/arch/xtensa/src/common/xtensa_dumpstate.c +++ b/arch/xtensa/src/common/xtensa_dumpstate.c @@ -163,7 +163,7 @@ void xtensa_dumpstate(void) uint32_t sp = xtensa_getsp(); uint32_t ustackbase; uint32_t ustacksize; -#ifdef HAVE_INTERRUPTSTACK +#if CONFIG_ARCH_INTERRUPTSTACK > 15 uint32_t istackbase; uint32_t istacksize; #endif @@ -185,10 +185,9 @@ void xtensa_dumpstate(void) /* Get the limits on the interrupt stack memory */ -#warning REVISIT interrupt stack -#ifdef HAVE_INTERRUPTSTACK - istackbase = (uint32_t)&g_intstack[INTERRUPT_STACKWORDS - 1]; - istacksize = INTERRUPTSTACK_SIZE; +#if CONFIG_ARCH_INTERRUPTSTACK > 15 + istackbase = (uint32_t)&g_intstackbase; + istacksize = (CONFIG_ARCH_INTERRUPTSTACK & ~15); /* Show interrupt stack info */ @@ -214,7 +213,7 @@ void xtensa_dumpstate(void) * at the base of the interrupt stack. */ - sp = &g_instack[INTERRUPTSTACK_SIZE - sizeof(uint32_t)]; + sp = g_intstackbase - sizeof(uint32_t); _alert("sp: %08x\n", sp); } else if (CURRENT_REGS) diff --git a/arch/xtensa/src/common/xtensa_initialize.c b/arch/xtensa/src/common/xtensa_initialize.c index aba916426c..082b99f389 100644 --- a/arch/xtensa/src/common/xtensa_initialize.c +++ b/arch/xtensa/src/common/xtensa_initialize.c @@ -58,6 +58,36 @@ #include "xtensa.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xtensa_color_intstack + * + * Description: + * Set the interrupt stack to a value so that later we can determine how + * much stack space was used by interrupt handling logic + * + ****************************************************************************/ + +#if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 15 +static inline void xtensa_color_intstack(void) +{ + ssize_t size; + uint32_t *ptr = (uint32_t *)&g_intstackalloc; + + for (size = (CONFIG_ARCH_INTERRUPTSTACK & ~15); + size > 0; + size -= sizeof(uint32_t)) + { + *ptr++ = INTSTACK_COLOR; + } +} +#else +# define xtensa_color_intstack() +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -81,6 +111,8 @@ void up_initialize(void) { + xtensa_color_intstack(); + #ifdef CONFIG_SMP int i; diff --git a/arch/xtensa/src/common/xtensa_int_handlers.S b/arch/xtensa/src/common/xtensa_int_handlers.S index eb591eeca4..02f83c4d7b 100644 --- a/arch/xtensa/src/common/xtensa_int_handlers.S +++ b/arch/xtensa/src/common/xtensa_int_handlers.S @@ -68,6 +68,19 @@ #include "chip_macros.h" #include "xtensa_timer.h" +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 + .data + .align 16 + .global g_intstackalloc + .global g_intstackbase + .type g_intstackalloc, @object + .type g_intstackbase, @object +g_intstackalloc: + .skip ((CONFIG_ARCH_INTERRUPTSTACK + 15) & ~15) +g_intstackbase: + .size g_intstackalloc, .-g_intstackalloc +#endif + /**************************************************************************** * Assembly Language Macros ****************************************************************************/ @@ -91,6 +104,21 @@ addi \aout, \aout, 1 /* Return aout + 1 */ .endm +/************************************************************************************ + * Name: setintstack + * + * Description: + * Set the current stack pointer to the "top" the interrupt stack. Single CPU + * case. Must be provided by MCU-specific logic in the SMP case. + * + ************************************************************************************/ + +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 + .macro setintstack + movi a1, g_intstackbase + .endm +#endif + /**************************************************************************** * Macro dispatch_c_isr level mask * @@ -112,6 +140,7 @@ * Entry Conditions/Side Effects: * level - interrupt level * mask - interrupt bitmask for this level + * a12 - register save area * * Exit Conditions: * This macro will use registers a0 and a2-a5 and a12. @@ -122,12 +151,6 @@ .macro dispatch_c_isr level mask - /* Initially the register save area is in SP, but that could change as - * a consequence of context switching. - */ - - mov a12, sp /* Address of save area */ - #ifdef __XTENSA_CALL0_ABI__ /* Get mask of pending, enabled interrupts at this level into a2. */ @@ -143,7 +166,7 @@ */ /* Argument 1: Set of CPU interrupt to dispatch */ - mov a3, sp /* Argument 2: Top of stack = register save area */ + mov a3, a12 /* Argument 2: Top of stack = register save area */ call0 xtensa_int_decode /* Call xtensa_int_decode */ /* On return from xtensa_int_decode, a2 will contain the address of the new @@ -169,7 +192,7 @@ */ /* Argument 1: Set of CPU interrupt to dispatch */ - mov a7, sp /* Argument 2: Top of stack = register save area */ + mov a7, a12 /* Argument 2: Top of stack = register save area */ call4 xtensa_int_decode /* Call xtensa_int_decode */ /* On return from xtensa_int_decode, a6 will contain the address of the new @@ -263,6 +286,19 @@ _xtensa_level1_handler: mov a2, sp /* Address of state save on stack */ call0 _xtensa_context_save /* Save full register state */ + /* Save current SP before (possibly) overwriting it, it's the register save + * area. This value will be used later by dispatch_c_isr to retrive the + * register save area. + */ + + mov a12, sp + + /* Switch to an interrupt stack if we have one */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 + setintstack +#endif + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ ps_setup 1 a0 diff --git a/arch/xtensa/src/esp32/esp32_irq.c b/arch/xtensa/src/esp32/esp32_irq.c index cb22cabc3c..65310a0e31 100644 --- a/arch/xtensa/src/esp32/esp32_irq.c +++ b/arch/xtensa/src/esp32/esp32_irq.c @@ -142,12 +142,6 @@ void up_irqinitialize(void) esp32_cpuint_initialize(); -#if defined(CONFIG_STACK_COLORATION) && defined(HAVE_INTERRUPTSTACK) - /* Colorize the interrupt stack for debug purposes */ - -#warning Missing logic -#endif - /* Attach and enable internal interrupts */ #ifdef CONFIG_SMP