Add abort() implementation
Also reduces the IRAM footprint of the fatal exception handler, as only the prelude (which disables interrupts & enables the flash mapping) is in IRAM now. Closes #54, relevant to #133.
This commit is contained in:
parent
6767891672
commit
b0844b01bc
9 changed files with 106 additions and 33 deletions
|
@ -40,8 +40,6 @@ void user_init(void);
|
||||||
#define RTCMEM_BACKUP_PHY_VER 31
|
#define RTCMEM_BACKUP_PHY_VER 31
|
||||||
#define RTCMEM_SYSTEM_PP_VER 62
|
#define RTCMEM_SYSTEM_PP_VER 62
|
||||||
|
|
||||||
#define halt() while (1) {}
|
|
||||||
|
|
||||||
extern uint32_t _bss_start;
|
extern uint32_t _bss_start;
|
||||||
extern uint32_t _bss_end;
|
extern uint32_t _bss_end;
|
||||||
|
|
||||||
|
@ -100,11 +98,11 @@ static void IRAM get_otp_mac_address(uint8_t *buf) {
|
||||||
if (!(otp_flags & 0x8000)) {
|
if (!(otp_flags & 0x8000)) {
|
||||||
//FIXME: do we really need this check?
|
//FIXME: do we really need this check?
|
||||||
printf("Firmware ONLY supports ESP8266!!!\n");
|
printf("Firmware ONLY supports ESP8266!!!\n");
|
||||||
halt();
|
abort();
|
||||||
}
|
}
|
||||||
if (otp_id0 == 0 && otp_id1 == 0) {
|
if (otp_id0 == 0 && otp_id1 == 0) {
|
||||||
printf("empty otp\n");
|
printf("empty otp\n");
|
||||||
halt();
|
abort();
|
||||||
}
|
}
|
||||||
if (otp_flags & 0x1000) {
|
if (otp_flags & 0x1000) {
|
||||||
// If bit 12 is set, it indicates that the vendor portion of the MAC
|
// If bit 12 is set, it indicates that the vendor portion of the MAC
|
||||||
|
@ -258,7 +256,7 @@ static void zero_bss(void) {
|
||||||
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr) {
|
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr) {
|
||||||
if (sdk_register_chipv6_phy(phy_info)) {
|
if (sdk_register_chipv6_phy(phy_info)) {
|
||||||
printf("FATAL: sdk_register_chipv6_phy failed");
|
printf("FATAL: sdk_register_chipv6_phy failed");
|
||||||
halt();
|
abort();
|
||||||
}
|
}
|
||||||
uart_set_baud(0, 74906);
|
uart_set_baud(0, 74906);
|
||||||
uart_set_baud(1, 74906);
|
uart_set_baud(1, 74906);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Code for dumping status/debug output/etc, including fatal
|
/* Code for dumping status/debug output/etc, including fatal
|
||||||
* exception handling.
|
* exception handling & abort implementation.
|
||||||
*
|
*
|
||||||
* Part of esp-open-rtos
|
* Part of esp-open-rtos
|
||||||
*
|
*
|
||||||
|
@ -20,7 +20,49 @@
|
||||||
#include "espressif/esp_common.h"
|
#include "espressif/esp_common.h"
|
||||||
#include "sdk_internal.h"
|
#include "sdk_internal.h"
|
||||||
|
|
||||||
void dump_excinfo(void) {
|
/* Forward declarations */
|
||||||
|
static void IRAM fatal_handler_prelude(void);
|
||||||
|
/* Inner parts of crash handlers marked noinline to ensure they don't inline into IRAM. */
|
||||||
|
static void __attribute__((noinline)) __attribute__((noreturn)) fatal_exception_handler_inner(uint32_t *sp);
|
||||||
|
static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_inner(uint32_t *caller, uint32_t *sp);
|
||||||
|
|
||||||
|
/* fatal_exception_handler called from any unhandled user exception
|
||||||
|
*
|
||||||
|
* (similar to a hard fault on other processor architectures)
|
||||||
|
*
|
||||||
|
* This function is run from IRAM, but the majority of the handler
|
||||||
|
* runs from flash after fatal_handler_prelude ensures it is mapped
|
||||||
|
* safely.
|
||||||
|
*/
|
||||||
|
void IRAM __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp) {
|
||||||
|
fatal_handler_prelude();
|
||||||
|
fatal_exception_handler_inner(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abort implementation
|
||||||
|
*
|
||||||
|
* Replaces the weak-linked abort implementation provided by newlib libc.
|
||||||
|
*
|
||||||
|
* Disable interrupts, enable flash mapping, dump stack & caller
|
||||||
|
* address, restart.
|
||||||
|
*
|
||||||
|
* This function is run from IRAM, but the majority of the abort
|
||||||
|
* handler runs from flash after fatal_handler_prelude ensures it is
|
||||||
|
* mapped safely.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void IRAM abort(void) {
|
||||||
|
uint32_t *sp, *caller;
|
||||||
|
RETADDR(caller);
|
||||||
|
/* abort() caller is one instruction before our return address */
|
||||||
|
caller = (uint32_t *)((intptr_t)caller - 3);
|
||||||
|
SP(sp);
|
||||||
|
fatal_handler_prelude();
|
||||||
|
abort_handler_inner(caller, sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump exception information from special function registers */
|
||||||
|
static void dump_excinfo(void) {
|
||||||
uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1;
|
uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1;
|
||||||
uint32_t excinfo[8];
|
uint32_t excinfo[8];
|
||||||
|
|
||||||
|
@ -50,9 +92,13 @@ void dump_excinfo(void) {
|
||||||
sdk_system_rtc_mem_write(0, excinfo, 32);
|
sdk_system_rtc_mem_write(0, excinfo, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There's a lot of smart stuff we could do while dumping stack
|
/* dump stack memory (frames above sp) to stdout
|
||||||
but for now we just dump a likely looking section of stack
|
|
||||||
memory
|
There's a lot of smart stuff we could do while dumping stack
|
||||||
|
but for now we just dump what looks like our stack region.
|
||||||
|
|
||||||
|
Probably dumps more memory than it needs to, the first instance of
|
||||||
|
0xa5a5a5a5 probably constitutes the end of our stack.
|
||||||
*/
|
*/
|
||||||
void dump_stack(uint32_t *sp) {
|
void dump_stack(uint32_t *sp) {
|
||||||
printf("\nStack: SP=%p\n", sp);
|
printf("\nStack: SP=%p\n", sp);
|
||||||
|
@ -68,10 +114,10 @@ void dump_stack(uint32_t *sp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump exception status registers as stored above 'sp'
|
/* Dump normal registers that were stored above 'sp'
|
||||||
by the interrupt handler preamble
|
by the exception handler preamble
|
||||||
*/
|
*/
|
||||||
void dump_exception_registers(uint32_t *sp) {
|
void dump_registers_in_exception_handler(uint32_t *sp) {
|
||||||
uint32_t excsave1;
|
uint32_t excsave1;
|
||||||
uint32_t *saved = sp - (0x50 / sizeof(uint32_t));
|
uint32_t *saved = sp - (0x50 / sizeof(uint32_t));
|
||||||
printf("Registers:\n");
|
printf("Registers:\n");
|
||||||
|
@ -84,7 +130,11 @@ void dump_exception_registers(uint32_t *sp) {
|
||||||
printf("SAR %08x\n", saved[0x13]);
|
printf("SAR %08x\n", saved[0x13]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM fatal_exception_handler(uint32_t *sp) {
|
|
||||||
|
/* Prelude ensures exceptions/NMI off and flash is mapped, allowing
|
||||||
|
calls to non-IRAM functions.
|
||||||
|
*/
|
||||||
|
static void IRAM fatal_handler_prelude(void) {
|
||||||
if (!sdk_NMIIrqIsOn) {
|
if (!sdk_NMIIrqIsOn) {
|
||||||
vPortEnterCritical();
|
vPortEnterCritical();
|
||||||
do {
|
do {
|
||||||
|
@ -93,9 +143,15 @@ void IRAM fatal_exception_handler(uint32_t *sp) {
|
||||||
}
|
}
|
||||||
Cache_Read_Disable();
|
Cache_Read_Disable();
|
||||||
Cache_Read_Enable(0, 0, 1);
|
Cache_Read_Enable(0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main part of fatal exception handler, is run from flash to save
|
||||||
|
some IRAM.
|
||||||
|
*/
|
||||||
|
static void fatal_exception_handler_inner(uint32_t *sp) {
|
||||||
dump_excinfo();
|
dump_excinfo();
|
||||||
if (sp) {
|
if (sp) {
|
||||||
dump_exception_registers(sp);
|
dump_registers_in_exception_handler(sp);
|
||||||
dump_stack(sp);
|
dump_stack(sp);
|
||||||
}
|
}
|
||||||
uart_flush_txfifo(0);
|
uart_flush_txfifo(0);
|
||||||
|
@ -103,3 +159,15 @@ void IRAM fatal_exception_handler(uint32_t *sp) {
|
||||||
sdk_system_restart_in_nmi();
|
sdk_system_restart_in_nmi();
|
||||||
while(1) {}
|
while(1) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Main part of abort handler, can be run from flash to save some
|
||||||
|
IRAM.
|
||||||
|
*/
|
||||||
|
static void abort_handler_inner(uint32_t *caller, uint32_t *sp) {
|
||||||
|
printf("abort() invoked at %p.\n", caller);
|
||||||
|
dump_stack(sp);
|
||||||
|
uart_flush_txfifo(0);
|
||||||
|
uart_flush_txfifo(1);
|
||||||
|
sdk_system_restart_in_nmi();
|
||||||
|
while(1) {}
|
||||||
|
}
|
||||||
|
|
|
@ -17,13 +17,6 @@ void dump_stack(uint32_t *sp);
|
||||||
|
|
||||||
Probably not useful to be called in other contexts.
|
Probably not useful to be called in other contexts.
|
||||||
*/
|
*/
|
||||||
void fatal_exception_handler(uint32_t *sp);
|
void __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp);
|
||||||
|
|
||||||
/* Dump the current exception register state.
|
|
||||||
|
|
||||||
Probably mostly useful when called from fatal exception handler.
|
|
||||||
*/
|
|
||||||
void dump_excinfo(void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,20 @@
|
||||||
// GCC macros for reading, writing, and exchanging Xtensa processor special
|
// GCC macros for reading, writing, and exchanging Xtensa processor special
|
||||||
// registers:
|
// registers:
|
||||||
|
|
||||||
|
/* Read stack pointer to variable.
|
||||||
|
*
|
||||||
|
* Note that the compiler will push a stack frame (minimum 16 bytes)
|
||||||
|
* in the prelude of a C function that calls any other functions.
|
||||||
|
*/
|
||||||
|
#define SP(var) asm volatile ("mov %0, a1" : "=r" (var));
|
||||||
|
|
||||||
|
/* Read the function return address to a variable.
|
||||||
|
*
|
||||||
|
* Depends on the containing function being simple enough that a0 is
|
||||||
|
* being used as a working register.
|
||||||
|
*/
|
||||||
|
#define RETADDR(var) asm volatile ("mov %0, a0" : "=r" (var))
|
||||||
|
|
||||||
#define RSR(var, reg) asm volatile ("rsr %0, " #reg : "=r" (var));
|
#define RSR(var, reg) asm volatile ("rsr %0, " #reg : "=r" (var));
|
||||||
#define WSR(var, reg) asm volatile ("wsr %0, " #reg : : "r" (var));
|
#define WSR(var, reg) asm volatile ("wsr %0, " #reg : : "r" (var));
|
||||||
#define XSR(var, reg) asm volatile ("xsr %0, " #reg : "+r" (var));
|
#define XSR(var, reg) asm volatile ("xsr %0, " #reg : "+r" (var));
|
||||||
|
|
|
@ -25,7 +25,7 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
|
||||||
if (heap_end + incr > stack_ptr)
|
if (heap_end + incr > stack_ptr)
|
||||||
{
|
{
|
||||||
_write (1, "_sbrk: Heap collided with stack\n", 32);
|
_write (1, "_sbrk: Heap collided with stack\n", 32);
|
||||||
while(1) {}
|
abort();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
heap_end += incr;
|
heap_end += incr;
|
||||||
|
|
|
@ -305,7 +305,7 @@ static void test_system_interaction()
|
||||||
}
|
}
|
||||||
uint32_t ticks = xTaskGetTickCount() - start;
|
uint32_t ticks = xTaskGetTickCount() - start;
|
||||||
printf("Timer interaction test PASSED after %dms.\n", ticks*portTICK_RATE_MS);
|
printf("Timer interaction test PASSED after %dms.\n", ticks*portTICK_RATE_MS);
|
||||||
while(1) {}
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following "sanity tests" are designed to try to execute every code path
|
/* The following "sanity tests" are designed to try to execute every code path
|
||||||
|
|
|
@ -115,7 +115,7 @@ void http_get_task(void *pvParameters)
|
||||||
strlen(pers))) != 0)
|
strlen(pers))) != 0)
|
||||||
{
|
{
|
||||||
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
||||||
while(1) {} /* todo: replace with abort() */
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" ok\n");
|
printf(" ok\n");
|
||||||
|
@ -129,7 +129,7 @@ void http_get_task(void *pvParameters)
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
{
|
{
|
||||||
printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
||||||
while(1) {} /* todo: replace with abort() */
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" ok (%d skipped)\n", ret);
|
printf(" ok (%d skipped)\n", ret);
|
||||||
|
@ -138,7 +138,7 @@ void http_get_task(void *pvParameters)
|
||||||
if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
|
if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
|
||||||
{
|
{
|
||||||
printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
|
printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
|
||||||
while(1) {} /* todo: replace with abort() */
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -85,7 +85,7 @@ void tls_server_task(void *pvParameters)
|
||||||
strlen(pers))) != 0)
|
strlen(pers))) != 0)
|
||||||
{
|
{
|
||||||
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
||||||
while(1) {} /* todo: replace with abort() */
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" ok\n");
|
printf(" ok\n");
|
||||||
|
@ -99,7 +99,7 @@ void tls_server_task(void *pvParameters)
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
{
|
{
|
||||||
printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
||||||
while(1) {} /* todo: replace with abort() */
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" ok (%d skipped)\n", ret);
|
printf(" ok (%d skipped)\n", ret);
|
||||||
|
@ -109,7 +109,7 @@ void tls_server_task(void *pvParameters)
|
||||||
if(ret != 0)
|
if(ret != 0)
|
||||||
{
|
{
|
||||||
printf(" failed\n ! mbedtls_pk_parse_key returned - 0x%x\n\n", -ret);
|
printf(" failed\n ! mbedtls_pk_parse_key returned - 0x%x\n\n", -ret);
|
||||||
while(1) { } /*todo: replace with abort() */
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" ok\n");
|
printf(" ok\n");
|
||||||
|
@ -134,7 +134,7 @@ void tls_server_task(void *pvParameters)
|
||||||
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
|
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
|
||||||
{
|
{
|
||||||
printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
|
printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
|
||||||
while(1) { }
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||||
|
|
|
@ -94,7 +94,7 @@ typedef int sys_prot_t;
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
} while(0)
|
} while(0)
|
||||||
#define LWIP_PLATFORM_ASSERT(x) do { printf("Assertion \"%s\" failed at line %d in %s\n", \
|
#define LWIP_PLATFORM_ASSERT(x) do { printf("Assertion \"%s\" failed at line %d in %s\n", \
|
||||||
x, __LINE__, __FILE__); while(1) {} } while(0)
|
x, __LINE__, __FILE__); abort(); } while(0)
|
||||||
|
|
||||||
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
|
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
|
||||||
printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \
|
printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \
|
||||||
|
|
Loading…
Reference in a new issue