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 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS
default 0x0 default 0x0
# Not implemented and/or needs new silicon rev to work
config MEMMAP_SPISRAM config MEMMAP_SPISRAM
bool "Use external SPI SRAM chip as main memory" bool "Use external SPI SRAM chip as main memory"
depends on ESP32_NEEDS_NEW_SILICON_REV
default "n" default "n"
help help
The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the 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 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 config INT_WDT
bool "Interrupt watchdog" bool "Interrupt watchdog"
default y default y

View File

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

View File

@ -24,7 +24,7 @@
#include "soc/uart_reg.h" #include "soc/uart_reg.h"
#include "soc/io_mux_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 //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. //implies a minimum size of about 320 bytes.

View File

@ -17,6 +17,6 @@
#include <xtensa/config/core.h> #include <xtensa/config/core.h>
#include "freertos/xtensa_api.h" #include "freertos/xtensa_api.h"
void gdbstubPanicHandler(XtExcFrame *frame); void esp_gdbstub_panic_handler(XtExcFrame *frame);
#endif #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 * @brief Initialize the interrupt watchdog. This is called in the init code if
* call it explicitly. * the interrupt watchdog is enabled in menuconfig.
* *
* @param null * @param null
* *
* @return null * @return null
*/ */
void int_wdt_init(); void esp_int_wdt_init();
/** /**

View File

@ -14,7 +14,7 @@
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
void setBreakpointIfJtag(void *fn); void esp_set_breakpoint_if_jtag(void *fn);
#endif #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 * @brief Initialize the task watchdog. This is called in the init code, if the
* call it explicitly. * task watchdog is enabled in menuconfig.
* *
* @param null * @param null
* *
* @return 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 * @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 * @return null
*/ */
void task_wdt_feed(); void esp_task_wdt_feed();
/** /**
@ -57,7 +67,7 @@ void task_wdt_feed();
* *
* @return null * @return null
*/ */
void task_wdt_delete(); void esp_task_wdt_delete();
/** /**
* @} * @}

View File

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

View File

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

View File

@ -13,18 +13,6 @@
// limitations under the License. // 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 "sdkconfig.h"
#include <stdint.h> #include <stdint.h>
@ -37,6 +25,7 @@ This uses the TIMERG1 WDT.
#include "esp_err.h" #include "esp_err.h"
#include "esp_intr.h" #include "esp_intr.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "esp_int_wdt.h" #include "esp_int_wdt.h"
@ -45,9 +34,8 @@ This uses the TIMERG1 WDT.
#define WDT_INT_NUM 24 #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_wprotect=WDT_WRITE_KEY;
TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS
TIMERG1.wdt_config0.cpu_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 #if CONFIG_INT_WDT_CHECK_CPU1
//Not static; the ISR assembly checks this. //Not static; the ISR assembly checks this.
bool int_wdt_app_cpu_ticked=false; bool int_wdt_app_cpu_ticked=false;

View File

@ -26,11 +26,10 @@
#include "soc/dport_reg.h" #include "soc/dport_reg.h"
#include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_reg.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "gdbstub.h" #include "esp_gdbstub.h"
#include "panic.h" #include "esp_panic.h"
#define WDT_WRITE_KEY 0x50D83AA1
/* /*
@ -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() { static void reconfigureAllWdts() {
TIMERG0.wdt_wprotect=WDT_WRITE_KEY; TIMERG0.wdt_wprotect=WDT_WRITE_KEY;
TIMERG0.wdt_feed=1; TIMERG0.wdt_feed=1;
@ -213,6 +218,9 @@ static void reconfigureAllWdts() {
TIMERG1.wdt_wprotect=0; TIMERG1.wdt_wprotect=0;
} }
/*
This disables all the watchdogs for when we call the gdbstub.
*/
static void disableAllWdts() { static void disableAllWdts() {
TIMERG0.wdt_wprotect=WDT_WRITE_KEY; TIMERG0.wdt_wprotect=WDT_WRITE_KEY;
TIMERG0.wdt_config0.en=0; TIMERG0.wdt_config0.en=0;
@ -254,7 +262,7 @@ void commonErrorHandler(XtExcFrame *frame) {
#if CONFIG_FREERTOS_PANIC_GDBSTUB #if CONFIG_FREERTOS_PANIC_GDBSTUB
disableAllWdts(); disableAllWdts();
panicPutStr("Entering gdb stub now.\r\n"); 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 #elif CONFIG_FREERTOS_PANIC_PRINT_REBOOT || CONFIG_FREERTOS_PANIC_SILENT_REBOOT
panicPutStr("Rebooting...\r\n"); panicPutStr("Rebooting...\r\n");
for (x=0; x<100; x++) ets_delay_us(1000); 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; if (!inOCDMode()) return;
setFirstBreakpoint((uint32_t)fn); setFirstBreakpoint((uint32_t)fn);
} }

View File

@ -13,14 +13,6 @@
// limitations under the License. // 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 <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -35,6 +27,7 @@ This uses the TIMERG0 WDT.
#include "esp_intr.h" #include "esp_intr.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
@ -52,11 +45,6 @@ struct wdt_task_t {
static wdt_task_t *wdt_task_list=NULL; 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) { static void IRAM_ATTR task_wdt_isr(void *arg) {
wdt_task_t *wdttask; wdt_task_t *wdttask;
const char *cpu; 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; wdt_task_t *wdttask=wdt_task_list;
bool found_task=false, do_feed_wdt=true; bool found_task=false, do_feed_wdt=true;
TaskHandle_t handle=xTaskGetCurrentTaskHandle(); 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(); TaskHandle_t handle=xTaskGetCurrentTaskHandle();
wdt_task_t *wdttask=wdt_task_list; wdt_task_t *wdttask=wdt_task_list;
//Wdt task list can't be empty //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_wprotect=WDT_WRITE_KEY;
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
TIMERG0.wdt_config0.cpu_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 !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
if (xPortGetCoreID()!=0) return; if (xPortGetCoreID()!=0) return;
#endif #endif
task_wdt_feed(); esp_task_wdt_feed();
} }
#endif #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. 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 choice FREERTOS_ASSERT
prompt "FreeRTOS assertions" prompt "FreeRTOS assertions"
default FREERTOS_ASSERT_FAIL_ABORT default FREERTOS_ASSERT_FAIL_ABORT

View File

@ -101,7 +101,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "panic.h" #include "esp_panic.h"
/* Defined in portasm.h */ /* Defined in portasm.h */
extern void _frxt_tick_timer_init(void); 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 #if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
void vPortFirstTaskHook(TaskFunction_t function) { void vPortFirstTaskHook(TaskFunction_t function) {
setBreakpointIfJtag(function); esp_set_breakpoint_if_jtag(function);
} }
#endif #endif

View File

@ -91,7 +91,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "xtensa_rtos.h" #include "xtensa_rtos.h"
#include "panic.h" #include "esp_panic.h"
#include "sdkconfig.h" #include "sdkconfig.h"
/* /*
Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used. Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used.