mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-07 16:23:38 +03:00
Increase free IRAM (#5499)
* Move functions out of IRAM when possible umm_init() is called in OS startup after flash is enabled, and never again. cont_get_free_stack() shouldn't be called from IRQ. Don't inline _iram_read_byte() function. * Move system fault handler to flash, use new printf The __wrap_system_restart call has been in flash for quite a while and seems to be working fine. There were some support routines that were placed in IRAM (mistakenly thinking the wrap_restart caller was also in IRAM) which are now moved to flash. Clean up the printf code to use the new stdlib which handles PGM_P strings as format and arguments without any difficulty. * Make STR macro more unique Add double-underscores to some string assistance macros to avoid conflicts with user applications. * Use function, not macro, to save code space Save ~2KB final bin size by using a ets_printf_P function and not an inline macro. IRAM and HEAP unaffected. * Don't actually touch the SP in the dump Store a copy of the incoming stack pointer in the postmortem in order to avoid actually changing the SP when a crash happend in BearSSL. * Make C++ uncaught exceptions explicit Use the term "Unhandled C++ exception" instead of just "Unhandled exception" to make it clear such crashes are caused by a C++ throw and now a system exception.
This commit is contained in:
parent
6324241e36
commit
8e46a3371d
@ -47,7 +47,8 @@ int ICACHE_RAM_ATTR cont_check(cont_t* cont) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ICACHE_RAM_ATTR cont_get_free_stack(cont_t* cont) {
|
// No need for this to be in IRAM, not expected to be IRQ called
|
||||||
|
int cont_get_free_stack(cont_t* cont) {
|
||||||
uint32_t *head = cont->stack;
|
uint32_t *head = cont->stack;
|
||||||
int freeWords = 0;
|
int freeWords = 0;
|
||||||
|
|
||||||
|
@ -62,32 +62,25 @@ extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack,
|
|||||||
|
|
||||||
extern void custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) __attribute__ ((weak, alias("__custom_crash_callback")));
|
extern void custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) __attribute__ ((weak, alias("__custom_crash_callback")));
|
||||||
|
|
||||||
// Single, non-inlined copy of pgm_read_byte to save IRAM space (as this is not timing critical)
|
|
||||||
static char ICACHE_RAM_ATTR iram_read_byte (const char *addr) {
|
|
||||||
return pgm_read_byte(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required to output the s_panic_file, it's stored in PMEM
|
// Prints need to use our library function to allow for file and function
|
||||||
#define ets_puts_P(pstr) \
|
// to be safely accessed from flash. This function encapsulates snprintf()
|
||||||
{ \
|
// [which by definition will 0-terminate] and dumping to the UART
|
||||||
char c; \
|
static void ets_printf_P(const char *str, ...) {
|
||||||
do { \
|
char destStr[160];
|
||||||
c = iram_read_byte(pstr++); \
|
char *c = destStr;
|
||||||
if (c) ets_putc(c); \
|
va_list argPtr;
|
||||||
} while (c); \
|
va_start(argPtr, str);
|
||||||
|
vsnprintf(destStr, sizeof(destStr), str, argPtr);
|
||||||
|
va_end(argPtr);
|
||||||
|
while (*c) {
|
||||||
|
ets_putc(*(c++));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place these strings in .text because the SPI interface may be in bad shape during an exception.
|
|
||||||
#define ets_printf_P(str, ...) \
|
|
||||||
{ \
|
|
||||||
static const char istr[] ICACHE_RAM_ATTR = (str); \
|
|
||||||
char mstr[sizeof(str)]; \
|
|
||||||
for (size_t i=0; i < sizeof(str); i++) mstr[i] = iram_read_byte(&istr[i]); \
|
|
||||||
ets_printf(mstr, ##__VA_ARGS__); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __wrap_system_restart_local() {
|
void __wrap_system_restart_local() {
|
||||||
register uint32_t sp asm("a1");
|
register uint32_t sp asm("a1");
|
||||||
|
uint32_t sp_dump = sp;
|
||||||
|
|
||||||
if (gdb_present()) {
|
if (gdb_present()) {
|
||||||
/* When GDBStub is present, exceptions are handled by GDBStub,
|
/* When GDBStub is present, exceptions are handled by GDBStub,
|
||||||
@ -110,28 +103,24 @@ void __wrap_system_restart_local() {
|
|||||||
ets_install_putc1(&uart_write_char_d);
|
ets_install_putc1(&uart_write_char_d);
|
||||||
|
|
||||||
if (s_panic_line) {
|
if (s_panic_line) {
|
||||||
ets_printf_P("\nPanic ");
|
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
|
||||||
ets_puts_P(s_panic_file); // This is in PROGMEM, need special output because ets_printf can't handle ROM parameters
|
|
||||||
ets_printf_P(":%d %s", s_panic_line, s_panic_func);
|
|
||||||
if (s_panic_what) {
|
if (s_panic_what) {
|
||||||
ets_printf_P(": Assertion '");
|
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
|
||||||
ets_puts_P(s_panic_what); // This is also in PMEM
|
|
||||||
ets_printf_P("' failed.");
|
|
||||||
}
|
}
|
||||||
ets_putc('\n');
|
ets_putc('\n');
|
||||||
}
|
}
|
||||||
else if (s_unhandled_exception) {
|
else if (s_unhandled_exception) {
|
||||||
ets_printf_P("\nUnhandled exception: %s\n", s_unhandled_exception);
|
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
|
||||||
}
|
}
|
||||||
else if (s_abort_called) {
|
else if (s_abort_called) {
|
||||||
ets_printf_P("\nAbort called\n");
|
ets_printf_P(PSTR("\nAbort called\n"));
|
||||||
}
|
}
|
||||||
else if (rst_info.reason == REASON_EXCEPTION_RST) {
|
else if (rst_info.reason == REASON_EXCEPTION_RST) {
|
||||||
ets_printf_P("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
|
ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"),
|
||||||
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
|
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
|
||||||
}
|
}
|
||||||
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
|
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
|
||||||
ets_printf_P("\nSoft WDT reset\n");
|
ets_printf_P(PSTR("\nSoft WDT reset\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cont_stack_start = (uint32_t) &(g_pcont->stack);
|
uint32_t cont_stack_start = (uint32_t) &(g_pcont->stack);
|
||||||
@ -152,54 +141,53 @@ void __wrap_system_restart_local() {
|
|||||||
offset = 0x10;
|
offset = 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
ets_printf_P("\n>>>stack>>>\n");
|
ets_printf_P(PSTR("\n>>>stack>>>\n"));
|
||||||
|
|
||||||
if (sp > stack_thunk_get_stack_bot() && sp <= stack_thunk_get_stack_top()) {
|
if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top()) {
|
||||||
// BearSSL we dump the BSSL second stack and then reset SP back to the main cont stack
|
// BearSSL we dump the BSSL second stack and then reset SP back to the main cont stack
|
||||||
ets_printf_P("\nctx: bearssl \n");
|
ets_printf_P(PSTR("\nctx: bearssl\nsp: %08x end: %08x offset: %04x\n"), sp_dump, stack_thunk_get_stack_top(), offset);
|
||||||
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_thunk_get_stack_top(), offset);
|
print_stack(sp_dump + offset, stack_thunk_get_stack_top());
|
||||||
print_stack(sp + offset, stack_thunk_get_stack_top());
|
|
||||||
offset = 0; // No offset needed anymore, the exception info was stored in the bssl stack
|
offset = 0; // No offset needed anymore, the exception info was stored in the bssl stack
|
||||||
sp = stack_thunk_get_cont_sp();
|
sp_dump = stack_thunk_get_cont_sp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sp > cont_stack_start && sp < cont_stack_end) {
|
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) {
|
||||||
ets_printf_P("\nctx: cont \n");
|
ets_printf_P(PSTR("\nctx: cont\n"));
|
||||||
stack_end = cont_stack_end;
|
stack_end = cont_stack_end;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ets_printf_P("\nctx: sys \n");
|
ets_printf_P(PSTR("\nctx: sys\n"));
|
||||||
stack_end = 0x3fffffb0;
|
stack_end = 0x3fffffb0;
|
||||||
// it's actually 0x3ffffff0, but the stuff below ets_run
|
// it's actually 0x3ffffff0, but the stuff below ets_run
|
||||||
// is likely not really relevant to the crash
|
// is likely not really relevant to the crash
|
||||||
}
|
}
|
||||||
|
|
||||||
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
|
ets_printf_P(PSTR("sp: %08x end: %08x offset: %04x\n"), sp_dump, stack_end, offset);
|
||||||
|
|
||||||
print_stack(sp + offset, stack_end);
|
print_stack(sp_dump + offset, stack_end);
|
||||||
|
|
||||||
ets_printf_P("<<<stack<<<\n");
|
ets_printf_P(PSTR("<<<stack<<<\n"));
|
||||||
|
|
||||||
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
|
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
|
||||||
if (umm_last_fail_alloc_addr) {
|
if (umm_last_fail_alloc_addr) {
|
||||||
ets_printf_P("\nlast failed alloc call: %08X(%d)\n", (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
|
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
custom_crash_callback( &rst_info, sp + offset, stack_end );
|
custom_crash_callback( &rst_info, sp_dump + offset, stack_end );
|
||||||
|
|
||||||
delayMicroseconds(10000);
|
delayMicroseconds(10000);
|
||||||
__real_system_restart_local();
|
__real_system_restart_local();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void ICACHE_RAM_ATTR print_stack(uint32_t start, uint32_t end) {
|
static void print_stack(uint32_t start, uint32_t end) {
|
||||||
for (uint32_t pos = start; pos < end; pos += 0x10) {
|
for (uint32_t pos = start; pos < end; pos += 0x10) {
|
||||||
uint32_t* values = (uint32_t*)(pos);
|
uint32_t* values = (uint32_t*)(pos);
|
||||||
|
|
||||||
// rough indicator: stack frames usually have SP saved as the second word
|
// rough indicator: stack frames usually have SP saved as the second word
|
||||||
bool looksLikeStackFrame = (values[2] == pos + 0x10);
|
bool looksLikeStackFrame = (values[2] == pos + 0x10);
|
||||||
|
|
||||||
ets_printf_P("%08x: %08x %08x %08x %08x %c\n",
|
ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"),
|
||||||
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
|
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
#include <core_version.h>
|
#include <core_version.h>
|
||||||
|
|
||||||
#define STRHELPER(x) #x
|
#define __STRHELPER(x) #x
|
||||||
#define STR(x) STRHELPER(x)
|
#define __STR(x) __STRHELPER(x)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C++"
|
extern "C++"
|
||||||
@ -111,7 +111,7 @@ namespace esp8266 {
|
|||||||
constexpr
|
constexpr
|
||||||
int coreVersionMajor ()
|
int coreVersionMajor ()
|
||||||
{
|
{
|
||||||
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 0);
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -120,7 +120,7 @@ int coreVersionMajor ()
|
|||||||
constexpr
|
constexpr
|
||||||
int coreVersionMinor ()
|
int coreVersionMinor ()
|
||||||
{
|
{
|
||||||
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 1);
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -129,7 +129,7 @@ int coreVersionMinor ()
|
|||||||
constexpr
|
constexpr
|
||||||
int coreVersionRevision ()
|
int coreVersionRevision ()
|
||||||
{
|
{
|
||||||
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 2);
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -139,7 +139,7 @@ int coreVersionRevision ()
|
|||||||
constexpr
|
constexpr
|
||||||
int coreVersionSubRevision ()
|
int coreVersionSubRevision ()
|
||||||
{
|
{
|
||||||
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 3);
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1202,8 +1202,9 @@ static unsigned short int umm_assimilate_down( unsigned short int c, unsigned sh
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* This function called only one time during OS startup after flash is */
|
||||||
void umm_init( void ) {
|
/* enabled. No need to keep it in IRAM. */
|
||||||
|
void ICACHE_FLASH_ATTR umm_init( void ) {
|
||||||
/* init heap pointer and size, and memset it to 0 */
|
/* init heap pointer and size, and memset it to 0 */
|
||||||
umm_heap = (umm_block *)UMM_MALLOC_CFG__HEAP_ADDR;
|
umm_heap = (umm_block *)UMM_MALLOC_CFG__HEAP_ADDR;
|
||||||
umm_numblocks = (UMM_MALLOC_CFG__HEAP_SIZE / sizeof(umm_block));
|
umm_numblocks = (UMM_MALLOC_CFG__HEAP_SIZE / sizeof(umm_block));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user