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_SYSTEM_PP_VER 62
|
||||
|
||||
#define halt() while (1) {}
|
||||
|
||||
extern uint32_t _bss_start;
|
||||
extern uint32_t _bss_end;
|
||||
|
||||
|
@ -100,11 +98,11 @@ static void IRAM get_otp_mac_address(uint8_t *buf) {
|
|||
if (!(otp_flags & 0x8000)) {
|
||||
//FIXME: do we really need this check?
|
||||
printf("Firmware ONLY supports ESP8266!!!\n");
|
||||
halt();
|
||||
abort();
|
||||
}
|
||||
if (otp_id0 == 0 && otp_id1 == 0) {
|
||||
printf("empty otp\n");
|
||||
halt();
|
||||
abort();
|
||||
}
|
||||
if (otp_flags & 0x1000) {
|
||||
// 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) {
|
||||
if (sdk_register_chipv6_phy(phy_info)) {
|
||||
printf("FATAL: sdk_register_chipv6_phy failed");
|
||||
halt();
|
||||
abort();
|
||||
}
|
||||
uart_set_baud(0, 74906);
|
||||
uart_set_baud(1, 74906);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Code for dumping status/debug output/etc, including fatal
|
||||
* exception handling.
|
||||
* exception handling & abort implementation.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
*
|
||||
|
@ -20,7 +20,49 @@
|
|||
#include "espressif/esp_common.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 excinfo[8];
|
||||
|
||||
|
@ -50,9 +92,13 @@ void dump_excinfo(void) {
|
|||
sdk_system_rtc_mem_write(0, excinfo, 32);
|
||||
}
|
||||
|
||||
/* There's a lot of smart stuff we could do while dumping stack
|
||||
but for now we just dump a likely looking section of stack
|
||||
memory
|
||||
/* dump stack memory (frames above sp) to stdout
|
||||
|
||||
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) {
|
||||
printf("\nStack: SP=%p\n", sp);
|
||||
|
@ -68,10 +114,10 @@ void dump_stack(uint32_t *sp) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Dump exception status registers as stored above 'sp'
|
||||
by the interrupt handler preamble
|
||||
/* Dump normal registers that were stored above 'sp'
|
||||
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 *saved = sp - (0x50 / sizeof(uint32_t));
|
||||
printf("Registers:\n");
|
||||
|
@ -84,7 +130,11 @@ void dump_exception_registers(uint32_t *sp) {
|
|||
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) {
|
||||
vPortEnterCritical();
|
||||
do {
|
||||
|
@ -93,9 +143,15 @@ void IRAM fatal_exception_handler(uint32_t *sp) {
|
|||
}
|
||||
Cache_Read_Disable();
|
||||
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();
|
||||
if (sp) {
|
||||
dump_exception_registers(sp);
|
||||
dump_registers_in_exception_handler(sp);
|
||||
dump_stack(sp);
|
||||
}
|
||||
uart_flush_txfifo(0);
|
||||
|
@ -103,3 +159,15 @@ void IRAM fatal_exception_handler(uint32_t *sp) {
|
|||
sdk_system_restart_in_nmi();
|
||||
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.
|
||||
*/
|
||||
void 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);
|
||||
|
||||
void __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,20 @@
|
|||
// GCC macros for reading, writing, and exchanging Xtensa processor special
|
||||
// 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 WSR(var, reg) asm volatile ("wsr %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)
|
||||
{
|
||||
_write (1, "_sbrk: Heap collided with stack\n", 32);
|
||||
while(1) {}
|
||||
abort();
|
||||
}
|
||||
*/
|
||||
heap_end += incr;
|
||||
|
|
|
@ -305,7 +305,7 @@ static void test_system_interaction()
|
|||
}
|
||||
uint32_t ticks = xTaskGetTickCount() - start;
|
||||
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
|
||||
|
|
|
@ -115,7 +115,7 @@ void http_get_task(void *pvParameters)
|
|||
strlen(pers))) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
abort();
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
@ -129,7 +129,7 @@ void http_get_task(void *pvParameters)
|
|||
if(ret < 0)
|
||||
{
|
||||
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);
|
||||
|
@ -138,7 +138,7 @@ void http_get_task(void *pvParameters)
|
|||
if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
abort();
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
@ -99,7 +99,7 @@ void tls_server_task(void *pvParameters)
|
|||
if(ret < 0)
|
||||
{
|
||||
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);
|
||||
|
@ -109,7 +109,7 @@ void tls_server_task(void *pvParameters)
|
|||
if(ret != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_pk_parse_key returned - 0x%x\n\n", -ret);
|
||||
while(1) { } /*todo: replace with abort() */
|
||||
abort();
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
@ -134,7 +134,7 @@ void tls_server_task(void *pvParameters)
|
|||
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -94,7 +94,7 @@ typedef int sys_prot_t;
|
|||
_Pragma("GCC diagnostic pop") \
|
||||
} while(0)
|
||||
#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)) { \
|
||||
printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \
|
||||
|
|
Loading…
Reference in a new issue