Xtensa/ESP32: Add Level1 handler, panic handler, remove EXECHOOKS.

This commit is contained in:
Gregory Nutt 2016-10-30 10:57:57 -06:00
parent eaa5968a22
commit fdede8099b
7 changed files with 350 additions and 106 deletions

View File

@ -50,6 +50,19 @@
* Pre-processor Definitions
****************************************************************************/
/* Exception Codes */
#define XTENSA_NMI_EXCEPTION 0
#define XTENSA_DEBUG_EXCEPTION 1
#define XTENSA_DOUBLE_EXCEPTION 2
#define XTENSA_KERNEL_EXCEPTION 3
#define XTENSA_COPROC_EXCEPTION 4
#define XTENSA_LEVEL2_EXCEPTION 5
#define XTENSA_LEVEL3_EXCEPTION 6
#define XTENSA_LEVEL4_EXCEPTION 7
#define XTENSA_LEVEL5_EXCEPTION 8
#define XTENSA_LEVEL6_EXCEPTION 9
/* Interrupt Matrix
*
* The Interrupt Matrix embedded in the ESP32 independently allocates

View File

@ -249,6 +249,7 @@ uint32_t *xtensa_int_decode(uint32_t *regs);
uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs);
uint32_t xtensa_enable_cpuint(uint32_t *shadow, uint32_t intmask);
uint32_t xtensa_disable_cpuint(uint32_t *shadow, uint32_t intmask);
void xtensa_panic(int xptcode, uint32_t *regs) noreturn_function;
/* Software interrupt handler */

View File

@ -158,3 +158,38 @@ void up_assert(const uint8_t *filename, int lineno)
xtensa_assert(EXIT_FAILURE);
}
/****************************************************************************
* Name: xtensa_panic
****************************************************************************/
void xtensa_panic(int xptcode, uint32_t *regs)
{
#if CONFIG_TASK_NAME_SIZE > 0 && defined(CONFIG_DEBUG_ALERT)
struct tcb_s *rtcb = this_task();
#endif
/* We get here when a un-dispatch-able, irrecoverable excpetion occurs */
board_autoled_on(LED_ASSERTION);
#if CONFIG_TASK_NAME_SIZE > 0
_alert("Unhandled Exception %d task: %s\n", xptcode, rtcb->name);
#else
_alert("Unhandled Exception %d\n", xptcode);
#endif
xtensa_dumpstate();
#ifdef CONFIG_ARCH_USBDUMP
/* Dump USB trace data */
(void)usbtrace_enumerate(assert_tracecallback, NULL);
#endif
#ifdef CONFIG_BOARD_CRASHDUMP
board_crashdump(up_getsp(), this_task(), filename, lineno);
#endif
xtensa_assert(EXIT_FAILURE);
}

View File

@ -127,25 +127,6 @@
and a2, a2, a4
beqz a2, 5f /* Nothing to do */
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a4, _xt_intexc_hooks
l32i a4, a4, \level << 2
beqz a4, 2f
#ifdef __XTENSA_CALL0_ABI__
callx0 a4
beqz a2, 5f
#else
mov a6, a2
callx4 a4
beqz a6, 5f
mov a2, a6
#endif
2:
#endif
/* If multiple bits are set then MSB has highest priority. */
extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */
@ -259,10 +240,63 @@
****************************************************************************/
/****************************************************************************
* LOW PRIORITY (LEVEL 1) LOW LEVEL HANDLER.
* LEVEL 1 INTERRUPT HANDLER
****************************************************************************/
/* The level1 interrupt vector is invoked via the User exception vector. */
#warning REVISIT level 1 interrupt handlers
.section HANDLER_SECTION, "ax"
.type _xtensa_level1_handler, @function
.align 4
_xtensa_level1_handler:
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, PS /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_1 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_1 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
/* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2)
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Set up PS for C, enable interrupts above this level and clear EXCM. */
ps_setup 1 a0
/* Decode and dispatch the interrupt. In the event of an interrupt
* level context dispatch_c_isr() will switch stacks to the new task's
* context save area.
*/
dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK
/* Restore registers in preparation to return from interrupt */
call0 _xtensa_context_restore
/* Restore only level-specific regs (the rest were already restored) */
l32i a0, sp, (4 * REG_PS) /* Retrieve interruptee's PS */
wsr a0, EPS_1
l32i a0, sp, (4 * REG_PC) /* Retrieve interruptee's PC */
wsr a0, EPC_1
l32i a0, sp, (4 * REG_A0) /* Retrieve interruptee's A0 */
l32i a2, sp, (4 * REG_A2) /* Retrieve interruptee's A2 */
l32i sp, sp, (4 * REG_A1) /* Remove interrupt stack frame */
rsync /* Ensure EPS and EPC written */
/* Return from interrupt. RFI restores the PS from EPS_1 and jumps to
* the address in EPC_1.
*/
rfi 1
/****************************************************************************
* MEDIUM PRIORITY (LEVEL 2+) INTERRUPT LOW LEVEL HANDLERS.
@ -310,7 +344,7 @@ _xtensa_level2_handler:
/* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2)
movi a2, sp /* Address of state save on stack */
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Set up PS for C, enable interrupts above this level and clear EXCM. */
@ -367,7 +401,7 @@ _xtensa_level3_handler:
/* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2)
movi a2, sp /* Address of state save on stack */
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Set up PS for C, enable interrupts above this level and clear EXCM. */
@ -424,7 +458,7 @@ _xtensa_level4_handler:
/* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2)
movi a2, sp /* Address of state save on stack */
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Set up PS for C, enable interrupts above this level and clear EXCM. */
@ -481,7 +515,7 @@ _xtensa_level5_handler:
/* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2)
movi a2, sp /* Address of state save on stack */
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Set up PS for C, enable interrupts above this level and clear EXCM. */
@ -538,7 +572,7 @@ _xtensa_level6_handler:
/* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2)
movi a2, sp /* Address of state save on stack */
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Set up PS for C, enable interrupts above this level and clear EXCM. */
@ -618,29 +652,30 @@ _xtensa_level6_handler:
_xtensa_level2_handler:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
#if 1
/* For now, just panic */
movi a0, _xt_intexc_hooks
l32i a0, a0, 2 << 2
beqz a0, 1f
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_2 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_2 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_2 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
.Ln_xtensa_level2_handler_call_hook:
s32i a2, sp, (4 * REG_A2)
movi a2, XTENSA_LEVEL2_EXCEPTION /* Address of state save on stack */
call0 _xtensa_panic /* Does not return */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
* ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
*/
.align 4
#else
/* Add high priority level 2 interrupt handler code here. */
rsr a0, EXCSAVE_2 /* Restore a0 */
rfi 2
#endif
#endif /* XCHAL_INT_NLEVELS >=2 && XCHAL_EXCM_LEVEL < 2 && XCHAL_DEBUGLEVEL !=2 */
#if XCHAL_INT_NLEVELS >=3 && XCHAL_EXCM_LEVEL < 3 && XCHAL_DEBUGLEVEL !=3
@ -650,28 +685,32 @@ _xtensa_level2_handler:
_xtensa_level3_handler:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
#if 1
/* For now, just panic */
movi a0, _xt_intexc_hooks
l32i a0, a0, 3 << 2
beqz a0, 1f
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_3 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_3 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_3 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
.Ln_xtensa_level3_handler_call_hook:
s32i a2, sp, (4 * REG_A2)
movi a2, XTENSA_LEVEL3_EXCEPTION /* Address of state save on stack */
call0 _xtensa_panic /* Does not return */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
#else
wsr a0, EXCSAVE_3 /* Save a0 */
/* USER_EDIT:
* ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
*/
.align 4
/* Add high priority level 2 interrupt handler code here. */
rsr a0, EXCSAVE_3 /* Restore a0 */
rfi 3
#endif
#endif /* XCHAL_INT_NLEVELS >=3 && XCHAL_EXCM_LEVEL < 3 && XCHAL_DEBUGLEVEL !=3 */
#if XCHAL_INT_NLEVELS >=4 && XCHAL_EXCM_LEVEL < 4 && XCHAL_DEBUGLEVEL !=4
@ -681,28 +720,32 @@ _xtensa_level3_handler:
_xtensa_level4_handler:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
#if 1
/* For now, just panic */
movi a0, _xt_intexc_hooks
l32i a0, a0, 4 << 2
beqz a0, 1f
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_4 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_4 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_4 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
.Ln_xtensa_level4_handler_call_hook:
s32i a2, sp, (4 * REG_A2)
movi a2, XTENSA_LEVEL4_EXCEPTION /* Address of state save on stack */
call0 _xtensa_panic /* Does not return */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
#else
wsr a0, EXCSAVE_4 /* Save a0 */
/* USER_EDIT:
* ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
*/
.align 4
/* Add high priority level 2 interrupt handler code here. */
rsr a0, EXCSAVE_4 /* Restore a0 */
rfi 4
#endif
#endif /* XCHAL_INT_NLEVELS >=4 && XCHAL_EXCM_LEVEL < 4 && XCHAL_DEBUGLEVEL !=4 */
#if XCHAL_INT_NLEVELS >=5 && XCHAL_EXCM_LEVEL < 5 && XCHAL_DEBUGLEVEL !=5
@ -712,26 +755,32 @@ _xtensa_level4_handler:
_xtensa_level5_handler:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
#if 1
/* For now, just panic */
movi a0, _xt_intexc_hooks
l32i a0, a0, 5 << 2
beqz a0, 1f
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_5 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_5 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_5 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
.Ln_xtensa_level5_handler_call_hook:
s32i a2, sp, (4 * REG_A2)
movi a2, XTENSA_LEVEL5_EXCEPTION /* Address of state save on stack */
call0 _xtensa_panic /* Does not return */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
#else
wsr a0, EXCSAVE_5 /* Save a0 */
/* USER_EDIT:
* ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
*/
/* Add high priority level 2 interrupt handler code here. */
rsr a0, EXCSAVE_5 /* Restore a0 */
rfi 5
#endif
#endif /* XCHAL_INT_NLEVELS >=5 && XCHAL_EXCM_LEVEL < 5 && XCHAL_DEBUGLEVEL !=5 */
#if XCHAL_INT_NLEVELS >=6 && XCHAL_EXCM_LEVEL < 6 && XCHAL_DEBUGLEVEL !=6
@ -741,24 +790,30 @@ _xtensa_level5_handler:
_xtensa_level6_handler:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
#if 1
/* For now, just panic */
movi a0, _xt_intexc_hooks
l32i a0, a0, 6 << 2
beqz a0, 1f
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_6 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_6 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_6 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
.Ln_xtensa_level6_handler_call_hook:
s32i a2, sp, (4 * REG_A2)
movi a2, XTENSA_LEVEL6_EXCEPTION /* Address of state save on stack */
call0 _xtensa_panic /* Does not return */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
#else
wsr a0, EXCSAVE_6 /* Save a0 */
/* USER_EDIT:
* ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
*/
/* Add high priority level 2 interrupt handler code here. */
rsr a0, EXCSAVE_6 /* Restore a0 */
rfi 6
#endif
#endif /* XCHAL_INT_NLEVELS >=6 && XCHAL_EXCM_LEVEL < 6 && XCHAL_DEBUGLEVEL !=6 */

View File

@ -59,6 +59,7 @@
#include <nuttx/config.h>
#include <arch/irq.h>
#include <arch/chip/core-isa.h>
#include <arch/xtensa/xtensa_specregs.h>
@ -103,23 +104,33 @@
#if XCHAL_HAVE_NMI
.section HANDLER_SECTION, "ax"
.type _xt_nmi, @function
.type _xtensa_nmi, @function
.align 4
_xt_nmi:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
_xtensa_nmi:
movi a0, _xt_intexc_hooks
l32i a0, a0, XCHAL_NMILEVEL << 2
beqz a0, 1f
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
#if 1
/* For now, just panic */
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_2 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_2 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_2 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
s32i a2, sp, (4 * REG_A2)
movi a2, XTENSA_NMI_EXCEPTION /* Address of state save on stack */
call0 _xtensa_panic /* Does not return */
#else
/* Add high priority non-maskable interrupt (NMI) handler code here. */
rsr a0, EXCSAVE + XCHAL_NMILEVEL /* Restore a0 */
rfi XCHAL_NMILEVEL
#endif
#endif /* XCHAL_HAVE_NMI */

View File

@ -0,0 +1,129 @@
/****************************************************************************
* arch/xtensa/src/common/xtensa_panic.S
*
* Adapted from use in NuttX by:
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derives from logic originally provided by Cadence Design Systems Inc.
*
* Copyright (c) 2006-2015 Cadence Design Systems Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
****************************************************************************/
.file "xtensa_panic.S"
/* NOTES on the use of 'call0' for long jumps instead of 'j':
*
* 1. This file should be assembled with the -mlongcalls option to xt-xcc.
*
* 2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to
* a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the
* distance from the call to the destination. The linker then relaxes
* it back to 'call0 dest' if it determines that dest is within range.
* This allows more flexibility in locating code without the performance
* overhead of the 'l32r' literal data load in cases where the destination
* is in range of 'call0'. There is an additional benefit in that 'call0'
* has a longer range than 'j' due to the target being word-aligned, so
* the 'l32r' sequence is less likely needed.
*
* 3. The use of 'call0' with -mlongcalls requires that register a0 not be
* live at the time of the call, which is always the case for a function
* call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'.
*
* 4. This use of 'call0' is independent of the C function call ABI.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/irq.h>
#include <arch/xtensa/core.h>
#include <arch/xtensa/xtensa_specregs.h>
/****************************************************************************
* Assembly Language Marcros
****************************************************************************/
/****************************************************************************
* Name: _xtensa_panic
*
* Description:
* Should be reached by call0 (preferable) or jump only. If call0, a0 says
* where from. If on simulator, display panic message and abort, else loop
* indefinitely.
*
* Entry Conditions:
* - A1 = Stack frame already allocated. SP points to beginning of the
* register frame.
* - A0, A1, A2, PC and PS = Already saved in the stack frame
* - A2 = Exception code
*
* Exit conditions:
* Does not return.
*
****************************************************************************/
.section HANDLER_SECTION, "ax"
.global _xtensa_panic
.type _xtensa_panic, @function
.align 4
.literal_position
.align 4
_xtensa_panic:
/* Save rest of interrupt context (A2=address of state save area on
* stack.
*/
mov a2, sp /* Address of state save on stack */
call0 _xtensa_context_save /* Save full register state */
/* Save exc cause and vaddr into exception frame */
rsr a0, EXCCAUSE
s32i a0, sp, (4 * REG_EXCCAUSE)
rsr a0, EXCVADDR
s32i a0, sp, (4 * REG_EXCVADDR)
/* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
mov a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
wsr a0, PS
/* Call C panic handler: Arg1 (A2) = Exception code; Arg 2 (A3) = start
* of the register save area.
*/
mov a3, sp
#ifdef __XTENSA_CALL0_ABI__
call0 xtensa_panic /* Call xtensa_panic. Should not return */
#else
call4 xtensa_panic /* Call xtensa_panic. Should not return */
#endif
1: j 1b /* loop infinitely */
retw

View File

@ -175,8 +175,8 @@ _xtensa_level6_vector:
_xtensa_nmi_vector:
wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */
call0 _xt_nmi /* load interrupt handler */
wsr a0, EXCSAVE + XCHAL_NMILEVEL /* Preserve a0 */
call0 _xtensa_nmi /* Load interrupt handler */
/* Never returns here - call0 is used as a jump */