Move panic handler and gdbstub into esp32 component, clean up wdt according to merge req suggestions

This commit is contained in:
Jeroen Domburg 2016-10-26 12:23:01 +08:00
parent 1ca97f5adb
commit 7d254eb3f0
15 changed files with 161 additions and 146 deletions

View file

@ -81,8 +81,10 @@ config TRACEMEM_RESERVE_DRAM
default 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS
default 0x0
# Not implemented and/or needs new silicon rev to work
config MEMMAP_SPISRAM
bool "Use external SPI SRAM chip as main memory"
depends on ESP32_NEEDS_NEW_SILICON_REV
default "n"
help
The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the
@ -153,6 +155,45 @@ config ULP_COPROC_RESERVE_MEM
depends on !ULP_COPROC_ENABLED
choice ESP32_PANIC
prompt "Panic handler behaviour"
default FREERTOS_PANIC_PRINT_REBOOT
help
If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is
invoked. Configure the panic handlers action here.
config ESP32_PANIC_PRINT_HALT
bool "Print registers and halt"
help
Outputs the relevant registers over the serial port and halt the
processor. Needs a manual reset to restart.
config ESP32_PANIC_PRINT_REBOOT
bool "Print registers and reboot"
help
Outputs the relevant registers over the serial port and immediately
reset the processor.
config ESP32_PANIC_SILENT_REBOOT
bool "Silent reboot"
help
Just resets the processor without outputting anything
config ESP32_PANIC_GDBSTUB
bool "Invoke GDBStub"
help
Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
of the crash.
endchoice
config ESP32_DEBUG_OCDAWARE
bool "Make exception and panic handlers JTAG/OCD aware"
default y
help
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
instead of panicking, have the debugger stop on the offending instruction.
config INT_WDT
bool "Interrupt watchdog"
default y

View file

@ -147,19 +147,19 @@ void start_cpu0_default(void)
#endif
esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
ets_setup_syscalls();
do_global_ctors();
esp_ipc_init();
spi_flash_init();
#if CONFIG_BROWNOUT_DET
esp_brownout_init();
#endif
#if CONFIG_INT_WDT
int_wdt_init();
esp_int_wdt_init();
#endif
#if CONFIG_TASK_WDT
task_wdt_init();
esp_task_wdt_init();
#endif
ets_setup_syscalls();
do_global_ctors();
esp_ipc_init();
spi_flash_init();
xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL,

View file

@ -24,7 +24,7 @@
#include "soc/uart_reg.h"
#include "soc/io_mux_reg.h"
#include "gdbstub.h"
#include "esp_gdbstub.h"
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
//implies a minimum size of about 320 bytes.

View file

@ -17,6 +17,6 @@
#include <xtensa/config/core.h>
#include "freertos/xtensa_api.h"
void gdbstubPanicHandler(XtExcFrame *frame);
void esp_gdbstub_panic_handler(XtExcFrame *frame);
#endif

View file

@ -23,15 +23,29 @@ extern "C" {
* @{
*/
/*
This routine enables a watchdog to catch instances of processes disabling
interrupts for too long, or code within interrupt handlers taking too long.
It does this by setting up a watchdog which gets fed from the FreeRTOS
task switch interrupt. When this watchdog times out, initially it will call
a high-level interrupt routine that will panic FreeRTOS in order to allow
for forensic examination of the state of the CPU. When this interrupt
handler is not called and the watchdog times out a second time, it will
reset the SoC.
This uses the TIMERG1 WDT.
*/
/**
* @brief Initialize the interrupt watchdog. This is called in the init code, no need to
* call it explicitly.
* @brief Initialize the interrupt watchdog. This is called in the init code if
* the interrupt watchdog is enabled in menuconfig.
*
* @param null
*
* @return null
*/
void int_wdt_init();
void esp_int_wdt_init();
/**

View file

@ -14,7 +14,7 @@
#ifndef __ASSEMBLER__
void setBreakpointIfJtag(void *fn);
void esp_set_breakpoint_if_jtag(void *fn);
#endif

View file

@ -28,15 +28,25 @@ extern "C" {
* @{
*/
/*
This routine enables a more general-purpose task watchdog: tasks can individually
feed the watchdog and the watchdog will bark if one or more tasks haven't fed the
watchdog within the specified time. Optionally, the idle tasks can also configured
to feed the watchdog in a similar fashion, to detect CPU starvation.
This uses the TIMERG0 WDT.
*/
/**
* @brief Initialize the task watchdog. This is called in the init code, no need to
* call it explicitly.
* @brief Initialize the task watchdog. This is called in the init code, if the
* task watchdog is enabled in menuconfig.
*
* @param null
*
* @return null
*/
void task_wdt_init();
void esp_task_wdt_init();
/**
* @brief Feed the watchdog. After the first feeding session, the watchdog will expect the calling
@ -47,7 +57,7 @@ void task_wdt_init();
* @return null
*/
void task_wdt_feed();
void esp_task_wdt_feed();
/**
@ -57,7 +67,7 @@ void task_wdt_feed();
*
* @return null
*/
void task_wdt_delete();
void esp_task_wdt_delete();
/**
* @}

View file

@ -14,6 +14,8 @@
#ifndef _SOC_RTC_CNTL_REG_H_
#define _SOC_RTC_CNTL_REG_H_
#define WDT_WRITE_KEY 0x50D83AA1
#include "soc.h"
#define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0)

View file

@ -15,6 +15,8 @@
#define __TIMG_REG_H__
#include "soc.h"
#define WDT_WRITE_KEY 0x50D83AA1
#define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000)
#define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000)
/* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */

View file

@ -13,18 +13,6 @@
// limitations under the License.
/*
This routine enables a watchdog to catch instances of processes disabling
interrupts for too long, or code within interrupt handlers taking too long.
It does this by setting up a watchdog which gets fed from the FreeRTOS
task switch interrupt. When this watchdog times out, initially it will call
a high-level interrupt routine that will panic FreeRTOS in order to allow
for forensic examination of the state of the CPU. When this interrupt
handler is not called and the watchdog times out a second time, it will
reset the SoC.
This uses the TIMERG1 WDT.
*/
#include "sdkconfig.h"
#include <stdint.h>
@ -37,6 +25,7 @@ This uses the TIMERG1 WDT.
#include "esp_err.h"
#include "esp_intr.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "esp_int_wdt.h"
@ -45,9 +34,8 @@ This uses the TIMERG1 WDT.
#define WDT_INT_NUM 24
#define WDT_WRITE_KEY 0x50D83AA1
void int_wdt_init() {
void esp_int_wdt_init() {
TIMERG1.wdt_wprotect=WDT_WRITE_KEY;
TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS
TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS
@ -73,6 +61,7 @@ void int_wdt_init() {
}
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
#if CONFIG_INT_WDT_CHECK_CPU1
//Not static; the ISR assembly checks this.
bool int_wdt_app_cpu_ticked=false;

View file

@ -26,11 +26,10 @@
#include "soc/dport_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "gdbstub.h"
#include "panic.h"
#define WDT_WRITE_KEY 0x50D83AA1
#include "esp_gdbstub.h"
#include "esp_panic.h"
/*
@ -196,7 +195,13 @@ void xt_unhandled_exception(XtExcFrame *frame) {
}
//Disables all but one WDT, and allows enough time on that WDT to do what we need to do.
/*
If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
one second.
*/
static void reconfigureAllWdts() {
TIMERG0.wdt_wprotect=WDT_WRITE_KEY;
TIMERG0.wdt_feed=1;
@ -213,6 +218,9 @@ static void reconfigureAllWdts() {
TIMERG1.wdt_wprotect=0;
}
/*
This disables all the watchdogs for when we call the gdbstub.
*/
static void disableAllWdts() {
TIMERG0.wdt_wprotect=WDT_WRITE_KEY;
TIMERG0.wdt_config0.en=0;
@ -254,7 +262,7 @@ void commonErrorHandler(XtExcFrame *frame) {
#if CONFIG_FREERTOS_PANIC_GDBSTUB
disableAllWdts();
panicPutStr("Entering gdb stub now.\r\n");
gdbstubPanicHandler(frame);
esp_gdbstub_panic_handler(frame);
#elif CONFIG_FREERTOS_PANIC_PRINT_REBOOT || CONFIG_FREERTOS_PANIC_SILENT_REBOOT
panicPutStr("Rebooting...\r\n");
for (x=0; x<100; x++) ets_delay_us(1000);
@ -267,7 +275,7 @@ void commonErrorHandler(XtExcFrame *frame) {
}
void setBreakpointIfJtag(void *fn) {
void esp_set_breakpoint_if_jtag(void *fn) {
if (!inOCDMode()) return;
setFirstBreakpoint((uint32_t)fn);
}

View file

@ -13,14 +13,6 @@
// limitations under the License.
/*
This routine enables a more general-purpose task watchdog: tasks can individually
feed the watchdog and the watchdog will bark if one or more tasks haven't fed the
watchdog within the specified time. Optionally, the idle tasks can also configured
to feed the watchdog in a similar fashion, to detect CPU starvation.
This uses the TIMERG0 WDT.
*/
#include <stdint.h>
#include <stdio.h>
@ -35,6 +27,7 @@ This uses the TIMERG0 WDT.
#include "esp_intr.h"
#include "esp_attr.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "esp_log.h"
#include "esp_task_wdt.h"
@ -52,11 +45,6 @@ struct wdt_task_t {
static wdt_task_t *wdt_task_list=NULL;
//We use this interrupt number on whatever task calls task_wdt_init.
#define WDT_INT_NUM 24
#define WDT_WRITE_KEY 0x50D83AA1
static void IRAM_ATTR task_wdt_isr(void *arg) {
wdt_task_t *wdttask;
const char *cpu;
@ -87,7 +75,7 @@ static void IRAM_ATTR task_wdt_isr(void *arg) {
}
void task_wdt_feed() {
void esp_task_wdt_feed() {
wdt_task_t *wdttask=wdt_task_list;
bool found_task=false, do_feed_wdt=true;
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
@ -127,7 +115,7 @@ void task_wdt_feed() {
}
}
void task_wdt_delete() {
void esp_task_wdt_delete() {
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
wdt_task_t *wdttask=wdt_task_list;
//Wdt task list can't be empty
@ -152,7 +140,7 @@ void task_wdt_delete() {
}
}
void task_wdt_init() {
void esp_task_wdt_init() {
TIMERG0.wdt_wprotect=WDT_WRITE_KEY;
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
@ -178,7 +166,7 @@ void vApplicationIdleHook(void) {
#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
if (xPortGetCoreID()!=0) return;
#endif
task_wdt_feed();
esp_task_wdt_feed();
}
#endif

View file

@ -93,45 +93,6 @@ config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
If using the WiFi stack, this value must be at least 1.
#This still needs to be implemented.
choice FREERTOS_PANIC
prompt "Panic handler behaviour"
default FREERTOS_PANIC_PRINT_REBOOT
help
If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is
invoked. Configure the panic handlers action here.
config FREERTOS_PANIC_PRINT_HALT
bool "Print registers and halt"
help
Outputs the relevant registers over the serial port and halt the
processor. Needs a manual reset to restart.
config FREERTOS_PANIC_PRINT_REBOOT
bool "Print registers and reboot"
help
Outputs the relevant registers over the serial port and immediately
reset the processor.
config FREERTOS_PANIC_SILENT_REBOOT
bool "Silent reboot"
help
Just resets the processor without outputting anything
config FREERTOS_PANIC_GDBSTUB
bool "Invoke GDBStub"
help
Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
of the crash.
endchoice
config FREERTOS_DEBUG_OCDAWARE
bool "Make exception and panic handlers JTAG/OCD aware"
default y
help
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
instead of panicking, have the debugger stop on the offending instruction.
choice FREERTOS_ASSERT
prompt "FreeRTOS assertions"
default FREERTOS_ASSERT_FAIL_ABORT

View file

@ -101,7 +101,7 @@
#include "FreeRTOS.h"
#include "task.h"
#include "panic.h"
#include "esp_panic.h"
/* Defined in portasm.h */
extern void _frxt_tick_timer_init(void);
@ -375,7 +375,7 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
void vPortFirstTaskHook(TaskFunction_t function) {
setBreakpointIfJtag(function);
esp_set_breakpoint_if_jtag(function);
}
#endif

View file

@ -91,7 +91,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/
#include "xtensa_rtos.h"
#include "panic.h"
#include "esp_panic.h"
#include "sdkconfig.h"
/*
Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used.
@ -303,12 +303,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
.section .iram1,"ax"
.global panicHandler
.global panicHandler
.global _xt_panic
.type _xt_panic,@function
.align 4
.literal_position
.literal_position
.align 4
_xt_panic:
@ -344,41 +344,41 @@ _xt_panic:
movi a0, PS_INTLEVEL(7) | PS_UM | PS_WOE
wsr a0, PS
//Call panic handler
mov a6,sp
call4 panicHandler
//Call panic handler
mov a6,sp
call4 panicHandler
1: j 1b /* loop infinitely */
retw
retw
.align 4
.align 4
//Call using call0. Prints the hex char in a2. Kills a3, a4, a5
panic_print_hex:
movi a3,0x60000000
movi a4,8
movi a3,0x60000000
movi a4,8
panic_print_hex_loop:
l32i a5, a3, 0x1c
extui a5, a5, 16, 8
bgei a5,64,panic_print_hex_loop
l32i a5, a3, 0x1c
extui a5, a5, 16, 8
bgei a5,64,panic_print_hex_loop
srli a5,a2,28
bgei a5,10,panic_print_hex_a
addi a5,a5,'0'
j panic_print_hex_ok
srli a5,a2,28
bgei a5,10,panic_print_hex_a
addi a5,a5,'0'
j panic_print_hex_ok
panic_print_hex_a:
addi a5,a5,'A'-10
addi a5,a5,'A'-10
panic_print_hex_ok:
s32i a5,a3,0
slli a2,a2,4
addi a4,a4,-1
bnei a4,0,panic_print_hex_loop
movi a5,' '
s32i a5,a3,0
s32i a5,a3,0
slli a2,a2,4
addi a4,a4,-1
bnei a4,0,panic_print_hex_loop
movi a5,' '
s32i a5,a3,0
ret
ret
@ -463,8 +463,8 @@ _DebugExceptionVector:
jx a3
#else
wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */
movi a0,PANIC_RSN_DEBUGEXCEPTION
wsr a0,EXCCAUSE
movi a0,PANIC_RSN_DEBUGEXCEPTION
wsr a0,EXCCAUSE
call0 _xt_panic /* does not return */
rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */
#endif
@ -492,8 +492,8 @@ _DoubleExceptionVector:
#if XCHAL_HAVE_DEBUG
break 1, 4 /* unhandled double exception */
#endif
movi a0,PANIC_RSN_DOUBLEEXCEPTION
wsr a0,EXCCAUSE
movi a0,PANIC_RSN_DOUBLEEXCEPTION
wsr a0,EXCCAUSE
call0 _xt_panic /* does not return */
rfde /* make a0 point here not later */
@ -527,8 +527,8 @@ _xt_kernel_exc:
#if XCHAL_HAVE_DEBUG
break 1, 0 /* unhandled kernel exception */
#endif
movi a0,PANIC_RSN_KERNELEXCEPTION
wsr a0,EXCCAUSE
movi a0,PANIC_RSN_KERNELEXCEPTION
wsr a0,EXCCAUSE
call0 _xt_panic /* does not return */
rfe /* make a0 point here not there */
@ -916,11 +916,11 @@ _xt_coproc_exc:
addi a2, a2, TASKTCB_XCOREID_OFFSET /* offset to xCoreID in tcb struct */
s32i a3, a2, 0 /* store current cpuid */
/* Grab correct xt_coproc_owner_sa for this core */
movi a2, XCHAL_CP_MAX << 2
mull a2, a2, a3
/* Grab correct xt_coproc_owner_sa for this core */
movi a2, XCHAL_CP_MAX << 2
mull a2, a2, a3
movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */
add a3, a3, a2
add a3, a3, a2
extui a2, a0, 0, 16 /* coprocessor bitmask portion */
or a4, a4, a2 /* a4 = CPENABLE | (1 << n) */
@ -1031,8 +1031,8 @@ _xt_coproc_exc:
#if XCHAL_HAVE_DEBUG
break 1, 1 /* unhandled user exception */
#endif
movi a0,PANIC_RSN_COPROCEXCEPTION
wsr a0,EXCCAUSE
movi a0,PANIC_RSN_COPROCEXCEPTION
wsr a0,EXCCAUSE
call0 _xt_panic /* not in a thread (invalid) */
/* never returns */
@ -1620,19 +1620,19 @@ _xt_highint4:
/* On the ESP32, this level is used for the INT_WDT handler. If that triggers, the program is stuck with interrupts
off and the CPU should panic. */
rsr a0, EXCSAVE_4
wsr a0, EXCSAVE_1 /* panic handler reads this register */
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
movi a0,PANIC_RSN_INTWDT_CPU0
wsr a0,EXCCAUSE
rsr a0, EXCSAVE_4
wsr a0, EXCSAVE_1 /* panic handler reads this register */
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
movi a0,PANIC_RSN_INTWDT_CPU0
wsr a0,EXCCAUSE
#if CONFIG_INT_WDT_CHECK_CPU1
/* Check if the cause is the app cpu failing to tick.*/
movi a0, int_wdt_app_cpu_ticked
l32i a0, a0, 0
bnez a0, 1f
/* It is. Modify cause. */
movi a0,PANIC_RSN_INTWDT_CPU1
wsr a0,EXCCAUSE
/* Check if the cause is the app cpu failing to tick.*/
movi a0, int_wdt_app_cpu_ticked
l32i a0, a0, 0
bnez a0, 1f
/* It is. Modify cause. */
movi a0,PANIC_RSN_INTWDT_CPU1
wsr a0,EXCCAUSE
1:
#endif
call0 _xt_panic