Merge branch 'feature/better_crash_dumps' into open-libmain
This commit is contained in:
commit
5fa17990dd
62 changed files with 5163 additions and 1355 deletions
|
@ -41,8 +41,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;
|
||||
|
||||
|
@ -85,7 +83,6 @@ static void IRAM set_spi0_divisor(uint32_t divisor);
|
|||
static void zero_bss(void);
|
||||
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr);
|
||||
static void init_g_ic(void);
|
||||
static void dump_excinfo(void);
|
||||
static void user_start_phase2(void);
|
||||
static void dump_flash_sector(uint32_t start_sector, uint32_t length);
|
||||
static void dump_flash_config_sectors(uint32_t start_sector);
|
||||
|
@ -102,11 +99,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
|
||||
|
@ -147,23 +144,6 @@ static void IRAM set_spi0_divisor(uint32_t divisor) {
|
|||
SPI(0).CTRL0 = SET_FIELD(SPI(0).CTRL0, SPI_CTRL0_CLOCK, clkdiv);
|
||||
}
|
||||
|
||||
// .text+0x148
|
||||
void IRAM sdk_user_fatal_exception_handler(void) {
|
||||
if (!sdk_NMIIrqIsOn) {
|
||||
vPortEnterCritical();
|
||||
do {
|
||||
DPORT.DPORT0 &= 0xffffffe0;
|
||||
} while (DPORT.DPORT0 & 0x00000001);
|
||||
}
|
||||
Cache_Read_Disable();
|
||||
Cache_Read_Enable(0, 0, 1);
|
||||
dump_excinfo();
|
||||
uart_flush_txfifo(0);
|
||||
uart_flush_txfifo(1);
|
||||
sdk_system_restart_in_nmi();
|
||||
halt();
|
||||
}
|
||||
|
||||
|
||||
static void IRAM default_putc(char c) {
|
||||
uart_putc(0, c);
|
||||
|
@ -277,7 +257,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);
|
||||
|
@ -333,37 +313,6 @@ static void init_g_ic(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// .Lfunc008 -- .irom0.text+0x2a0
|
||||
static void dump_excinfo(void) {
|
||||
uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1;
|
||||
uint32_t excinfo[8];
|
||||
|
||||
RSR(exccause, exccause);
|
||||
printf("Fatal exception (%d): \n", (int)exccause);
|
||||
RSR(epc1, epc1);
|
||||
RSR(epc2, epc2);
|
||||
RSR(epc3, epc3);
|
||||
RSR(excvaddr, excvaddr);
|
||||
RSR(depc, depc);
|
||||
RSR(excsave1, excsave1);
|
||||
printf("%s=0x%08x\n", "epc1", epc1);
|
||||
printf("%s=0x%08x\n", "epc2", epc2);
|
||||
printf("%s=0x%08x\n", "epc3", epc3);
|
||||
printf("%s=0x%08x\n", "excvaddr", excvaddr);
|
||||
printf("%s=0x%08x\n", "depc", depc);
|
||||
printf("%s=0x%08x\n", "excsave1", excsave1);
|
||||
sdk_system_rtc_mem_read(0, excinfo, 32); // Why?
|
||||
excinfo[0] = 2;
|
||||
excinfo[1] = exccause;
|
||||
excinfo[2] = epc1;
|
||||
excinfo[3] = epc2;
|
||||
excinfo[4] = epc3;
|
||||
excinfo[5] = excvaddr;
|
||||
excinfo[6] = depc;
|
||||
excinfo[7] = excsave1;
|
||||
sdk_system_rtc_mem_write(0, excinfo, 32);
|
||||
}
|
||||
|
||||
// .irom0.text+0x398
|
||||
void sdk_wdt_init(void) {
|
||||
WDT.CTRL &= ~WDT_CTRL_ENABLE;
|
||||
|
@ -408,6 +357,9 @@ void sdk_user_init_task(void *params) {
|
|||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
|
||||
// .Lfunc009 -- .irom0.text+0x5b4
|
||||
static void user_start_phase2(void) {
|
||||
uint8_t *buf;
|
||||
|
@ -445,6 +397,13 @@ static void user_start_phase2(void) {
|
|||
}
|
||||
init_networking(phy_info, sdk_info.sta_mac_addr);
|
||||
free(phy_info);
|
||||
|
||||
// Call gcc constructor functions
|
||||
void (**ctor)(void);
|
||||
for ( ctor = &__init_array_start; ctor != &__init_array_end; ++ctor) {
|
||||
(*ctor)();
|
||||
}
|
||||
|
||||
tcpip_init(NULL, NULL);
|
||||
sdk_wdt_init();
|
||||
xTaskCreate(sdk_user_init_task, (signed char *)"uiT", 1024, 0, 14, &sdk_xUserTaskHandle);
|
||||
|
|
175
core/debug_dumps.c
Normal file
175
core/debug_dumps.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* Code for dumping status/debug output/etc, including fatal
|
||||
* exception handling & abort implementation.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
*
|
||||
* Partially reverse engineered from MIT licensed Espressif RTOS SDK Copyright (C) Espressif Systems.
|
||||
* Additions Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#include "debug_dumps.h"
|
||||
#include "common_macros.h"
|
||||
#include "xtensa_ops.h"
|
||||
#include "esp/rom.h"
|
||||
#include "esp/uart.h"
|
||||
#include "espressif/esp_common.h"
|
||||
#include "sdk_internal.h"
|
||||
|
||||
/* 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, bool registers_saved_on_stack);
|
||||
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, bool registers_saved_on_stack) {
|
||||
fatal_handler_prelude();
|
||||
fatal_exception_handler_inner(sp, registers_saved_on_stack);
|
||||
}
|
||||
|
||||
/* 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];
|
||||
|
||||
RSR(exccause, exccause);
|
||||
printf("Fatal exception (%d): \n", (int)exccause);
|
||||
RSR(epc1, epc1);
|
||||
RSR(epc2, epc2);
|
||||
RSR(epc3, epc3);
|
||||
RSR(excvaddr, excvaddr);
|
||||
RSR(depc, depc);
|
||||
RSR(excsave1, excsave1);
|
||||
printf("%s=0x%08x\n", "epc1", epc1);
|
||||
printf("%s=0x%08x\n", "epc2", epc2);
|
||||
printf("%s=0x%08x\n", "epc3", epc3);
|
||||
printf("%s=0x%08x\n", "excvaddr", excvaddr);
|
||||
printf("%s=0x%08x\n", "depc", depc);
|
||||
printf("%s=0x%08x\n", "excsave1", excsave1);
|
||||
sdk_system_rtc_mem_read(0, excinfo, 32); // Why?
|
||||
excinfo[0] = 2;
|
||||
excinfo[1] = exccause;
|
||||
excinfo[2] = epc1;
|
||||
excinfo[3] = epc2;
|
||||
excinfo[4] = epc3;
|
||||
excinfo[5] = excvaddr;
|
||||
excinfo[6] = depc;
|
||||
excinfo[7] = excsave1;
|
||||
sdk_system_rtc_mem_write(0, excinfo, 32);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
for(uint32_t *p = sp; p < sp + 32; p += 4) {
|
||||
if((intptr_t)p >= 0x3fffc000) {
|
||||
break; /* approximate end of RAM */
|
||||
}
|
||||
printf("%p: %08x %08x %08x %08x\n", p, p[0], p[1], p[2], p[3]);
|
||||
if(p[0] == 0xa5a5a5a5 && p[1] == 0xa5a5a5a5
|
||||
&& p[2] == 0xa5a5a5a5 && p[3] == 0xa5a5a5a5) {
|
||||
break; /* FreeRTOS uses this pattern to mark untouched stack space */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump normal registers that were stored above 'sp'
|
||||
by the exception handler preamble
|
||||
*/
|
||||
void dump_registers_in_exception_handler(uint32_t *sp) {
|
||||
uint32_t excsave1;
|
||||
uint32_t *saved = sp - (0x50 / sizeof(uint32_t));
|
||||
printf("Registers:\n");
|
||||
RSR(excsave1, excsave1);
|
||||
printf("a0 %08x ", excsave1);
|
||||
printf("a1 %08x ", (intptr_t)sp);
|
||||
for(int a = 2; a < 14; a++) {
|
||||
printf("a%-2d %08x%c", a, saved[a+3], a == 3 || a == 7 || a == 11 ? '\n':' ');
|
||||
}
|
||||
printf("SAR %08x\n", saved[0x13]);
|
||||
}
|
||||
|
||||
|
||||
/* 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 {
|
||||
DPORT.DPORT0 &= 0xffffffe0;
|
||||
} while (DPORT.DPORT0 & 0x00000001);
|
||||
}
|
||||
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, bool registers_saved_on_stack) {
|
||||
dump_excinfo();
|
||||
if (sp) {
|
||||
if (registers_saved_on_stack) {
|
||||
dump_registers_in_exception_handler(sp);
|
||||
}
|
||||
dump_stack(sp);
|
||||
}
|
||||
uart_flush_txfifo(0);
|
||||
uart_flush_txfifo(1);
|
||||
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) {}
|
||||
}
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
_xt_isr isr[16];
|
||||
|
||||
bool esp_in_isr;
|
||||
|
||||
void IRAM _xt_isr_attach(uint8_t i, _xt_isr func)
|
||||
{
|
||||
isr[i] = func;
|
||||
|
@ -20,6 +22,8 @@ void IRAM _xt_isr_attach(uint8_t i, _xt_isr func)
|
|||
*/
|
||||
uint16_t IRAM _xt_isr_handler(uint16_t intset)
|
||||
{
|
||||
esp_in_isr = true;
|
||||
|
||||
/* WDT has highest priority (occasional WDT resets otherwise) */
|
||||
if(intset & BIT(INUM_WDT)) {
|
||||
_xt_clear_ints(BIT(INUM_WDT));
|
||||
|
@ -35,5 +39,7 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset)
|
|||
intset -= mask;
|
||||
}
|
||||
|
||||
esp_in_isr = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,9 @@ DebugExceptionVector:
|
|||
.type DebugExceptionVector, @function
|
||||
|
||||
wsr a0, excsave2
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
mov a2, a1
|
||||
movi a3, 0
|
||||
call0 fatal_exception_handler
|
||||
rfi 2
|
||||
|
||||
.org VecBase + 0x20
|
||||
|
@ -81,7 +83,9 @@ KernelExceptionVector:
|
|||
.type KernelExceptionVector, @function
|
||||
|
||||
break 1, 0
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
mov a2, a1
|
||||
movi a3, 0
|
||||
call0 fatal_exception_handler
|
||||
rfe
|
||||
|
||||
.org VecBase + 0x50
|
||||
|
@ -98,7 +102,9 @@ DoubleExceptionVector:
|
|||
.type DoubleExceptionVector, @function
|
||||
|
||||
break 1, 4
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
mov a2, a1
|
||||
movi a3, 0
|
||||
call0 fatal_exception_handler
|
||||
|
||||
/* Reset vector at offset 0x80 is unused, as vecbase gets reset to mask ROM
|
||||
* vectors on chip reset. */
|
||||
|
@ -251,11 +257,13 @@ LoadStoreErrorHandler:
|
|||
* will have correct values */
|
||||
wsr a0, sar
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
/*l32i a2, sp, 0x08*/
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
mov a2, a1
|
||||
movi a3, 0
|
||||
call0 fatal_exception_handler
|
||||
|
||||
.balign 4
|
||||
.LSE_assign_a1:
|
||||
|
@ -515,7 +523,9 @@ UserExceptionHandler:
|
|||
.literal_position
|
||||
.LUserFailOtherExceptionCause:
|
||||
break 1, 1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
addi a2, a1, 0x50 /* UserExceptionHandler pushes stack down 0x50 */
|
||||
movi a3, 1
|
||||
call0 fatal_exception_handler
|
||||
|
||||
/* _xt_user_exit is pushed onto the stack as part of the user exception handler,
|
||||
restores same set registers which were saved there and returns from exception */
|
||||
|
|
22
core/include/debug_dumps.h
Normal file
22
core/include/debug_dumps.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* Functions for dumping status/debug output/etc, including fatal
|
||||
* exception handling.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
*
|
||||
* Copyright (C) 2015-2016 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _DEBUG_DUMPS_H
|
||||
#define _DEBUG_DUMPS_H
|
||||
#include <stdint.h>
|
||||
|
||||
/* Dump stack memory starting from stack pointer address sp. */
|
||||
void dump_stack(uint32_t *sp);
|
||||
|
||||
/* Called from exception_vectors.S when a fatal exception occurs.
|
||||
|
||||
Probably not useful to be called in other contexts.
|
||||
*/
|
||||
void __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp, bool registers_saved_on_stack);
|
||||
|
||||
#endif
|
|
@ -25,4 +25,19 @@
|
|||
#define ESYNC() asm volatile ( "esync" )
|
||||
#define DSYNC() asm volatile ( "dsync" )
|
||||
|
||||
|
||||
/* 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))
|
||||
|
||||
#endif /* _XTENSA_OPS_H */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -17,20 +17,6 @@ void IRAM *zalloc(size_t nbytes)
|
|||
return calloc(1, nbytes);
|
||||
}
|
||||
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
|
||||
/* Do things which should be done as part of the SDK startup code, but aren't.
|
||||
TODO: Move into app_main.c
|
||||
*/
|
||||
void sdk_compat_initialise()
|
||||
{
|
||||
/* Call C++ constructors or C functions marked with __attribute__((constructor)) */
|
||||
void (**p)(void);
|
||||
for ( p = &__init_array_start; p != &__init_array_end; ++p)
|
||||
(*p)();
|
||||
}
|
||||
|
||||
/* UART RX function from Espressif SDK internals.
|
||||
*
|
||||
* Not part of published API.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue