Skip to content

Commit 8e46a33

Browse files
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.
1 parent 6324241 commit 8e46a33

File tree

4 files changed

+46
-56
lines changed

4 files changed

+46
-56
lines changed

Diff for: cores/esp8266/cont_util.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ int ICACHE_RAM_ATTR cont_check(cont_t* cont) {
4747
return 0;
4848
}
4949

50-
int ICACHE_RAM_ATTR cont_get_free_stack(cont_t* cont) {
50+
// No need for this to be in IRAM, not expected to be IRQ called
51+
int cont_get_free_stack(cont_t* cont) {
5152
uint32_t *head = cont->stack;
5253
int freeWords = 0;
5354

Diff for: cores/esp8266/core_esp8266_postmortem.c

+35-47
Original file line numberDiff line numberDiff line change
@@ -62,32 +62,25 @@ extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack,
6262

6363
extern void custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) __attribute__ ((weak, alias("__custom_crash_callback")));
6464

65-
// Single, non-inlined copy of pgm_read_byte to save IRAM space (as this is not timing critical)
66-
static char ICACHE_RAM_ATTR iram_read_byte (const char *addr) {
67-
return pgm_read_byte(addr);
68-
}
69-
70-
// Required to output the s_panic_file, it's stored in PMEM
71-
#define ets_puts_P(pstr) \
72-
{ \
73-
char c; \
74-
do { \
75-
c = iram_read_byte(pstr++); \
76-
if (c) ets_putc(c); \
77-
} while (c); \
78-
}
7965

80-
// Place these strings in .text because the SPI interface may be in bad shape during an exception.
81-
#define ets_printf_P(str, ...) \
82-
{ \
83-
static const char istr[] ICACHE_RAM_ATTR = (str); \
84-
char mstr[sizeof(str)]; \
85-
for (size_t i=0; i < sizeof(str); i++) mstr[i] = iram_read_byte(&istr[i]); \
86-
ets_printf(mstr, ##__VA_ARGS__); \
66+
// Prints need to use our library function to allow for file and function
67+
// to be safely accessed from flash. This function encapsulates snprintf()
68+
// [which by definition will 0-terminate] and dumping to the UART
69+
static void ets_printf_P(const char *str, ...) {
70+
char destStr[160];
71+
char *c = destStr;
72+
va_list argPtr;
73+
va_start(argPtr, str);
74+
vsnprintf(destStr, sizeof(destStr), str, argPtr);
75+
va_end(argPtr);
76+
while (*c) {
77+
ets_putc(*(c++));
78+
}
8779
}
8880

8981
void __wrap_system_restart_local() {
9082
register uint32_t sp asm("a1");
83+
uint32_t sp_dump = sp;
9184

9285
if (gdb_present()) {
9386
/* When GDBStub is present, exceptions are handled by GDBStub,
@@ -110,28 +103,24 @@ void __wrap_system_restart_local() {
110103
ets_install_putc1(&uart_write_char_d);
111104

112105
if (s_panic_line) {
113-
ets_printf_P("\nPanic ");
114-
ets_puts_P(s_panic_file); // This is in PROGMEM, need special output because ets_printf can't handle ROM parameters
115-
ets_printf_P(":%d %s", s_panic_line, s_panic_func);
106+
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
116107
if (s_panic_what) {
117-
ets_printf_P(": Assertion '");
118-
ets_puts_P(s_panic_what); // This is also in PMEM
119-
ets_printf_P("' failed.");
108+
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
120109
}
121110
ets_putc('\n');
122111
}
123112
else if (s_unhandled_exception) {
124-
ets_printf_P("\nUnhandled exception: %s\n", s_unhandled_exception);
113+
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
125114
}
126115
else if (s_abort_called) {
127-
ets_printf_P("\nAbort called\n");
116+
ets_printf_P(PSTR("\nAbort called\n"));
128117
}
129118
else if (rst_info.reason == REASON_EXCEPTION_RST) {
130-
ets_printf_P("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
119+
ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"),
131120
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
132121
}
133122
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
134-
ets_printf_P("\nSoft WDT reset\n");
123+
ets_printf_P(PSTR("\nSoft WDT reset\n"));
135124
}
136125

137126
uint32_t cont_stack_start = (uint32_t) &(g_pcont->stack);
@@ -152,54 +141,53 @@ void __wrap_system_restart_local() {
152141
offset = 0x10;
153142
}
154143

155-
ets_printf_P("\n>>>stack>>>\n");
144+
ets_printf_P(PSTR("\n>>>stack>>>\n"));
156145

157-
if (sp > stack_thunk_get_stack_bot() && sp <= stack_thunk_get_stack_top()) {
146+
if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top()) {
158147
// BearSSL we dump the BSSL second stack and then reset SP back to the main cont stack
159-
ets_printf_P("\nctx: bearssl \n");
160-
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_thunk_get_stack_top(), offset);
161-
print_stack(sp + offset, stack_thunk_get_stack_top());
148+
ets_printf_P(PSTR("\nctx: bearssl\nsp: %08x end: %08x offset: %04x\n"), sp_dump, stack_thunk_get_stack_top(), offset);
149+
print_stack(sp_dump + offset, stack_thunk_get_stack_top());
162150
offset = 0; // No offset needed anymore, the exception info was stored in the bssl stack
163-
sp = stack_thunk_get_cont_sp();
151+
sp_dump = stack_thunk_get_cont_sp();
164152
}
165153

166-
if (sp > cont_stack_start && sp < cont_stack_end) {
167-
ets_printf_P("\nctx: cont \n");
154+
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) {
155+
ets_printf_P(PSTR("\nctx: cont\n"));
168156
stack_end = cont_stack_end;
169157
}
170158
else {
171-
ets_printf_P("\nctx: sys \n");
159+
ets_printf_P(PSTR("\nctx: sys\n"));
172160
stack_end = 0x3fffffb0;
173161
// it's actually 0x3ffffff0, but the stuff below ets_run
174162
// is likely not really relevant to the crash
175163
}
176164

177-
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
165+
ets_printf_P(PSTR("sp: %08x end: %08x offset: %04x\n"), sp_dump, stack_end, offset);
178166

179-
print_stack(sp + offset, stack_end);
167+
print_stack(sp_dump + offset, stack_end);
180168

181-
ets_printf_P("<<<stack<<<\n");
169+
ets_printf_P(PSTR("<<<stack<<<\n"));
182170

183171
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
184172
if (umm_last_fail_alloc_addr) {
185-
ets_printf_P("\nlast failed alloc call: %08X(%d)\n", (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
173+
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
186174
}
187175

188-
custom_crash_callback( &rst_info, sp + offset, stack_end );
176+
custom_crash_callback( &rst_info, sp_dump + offset, stack_end );
189177

190178
delayMicroseconds(10000);
191179
__real_system_restart_local();
192180
}
193181

194182

195-
static void ICACHE_RAM_ATTR print_stack(uint32_t start, uint32_t end) {
183+
static void print_stack(uint32_t start, uint32_t end) {
196184
for (uint32_t pos = start; pos < end; pos += 0x10) {
197185
uint32_t* values = (uint32_t*)(pos);
198186

199187
// rough indicator: stack frames usually have SP saved as the second word
200188
bool looksLikeStackFrame = (values[2] == pos + 0x10);
201189

202-
ets_printf_P("%08x: %08x %08x %08x %08x %c\n",
190+
ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"),
203191
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
204192
}
205193
}

Diff for: cores/esp8266/core_esp8266_version.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424

2525
#include <core_version.h>
2626

27-
#define STRHELPER(x) #x
28-
#define STR(x) STRHELPER(x)
27+
#define __STRHELPER(x) #x
28+
#define __STR(x) __STRHELPER(x)
2929

3030
#ifdef __cplusplus
3131
extern "C++"
@@ -111,7 +111,7 @@ namespace esp8266 {
111111
constexpr
112112
int coreVersionMajor ()
113113
{
114-
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 0);
114+
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0);
115115
}
116116

117117
/*
@@ -120,7 +120,7 @@ int coreVersionMajor ()
120120
constexpr
121121
int coreVersionMinor ()
122122
{
123-
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 1);
123+
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1);
124124
}
125125

126126
/*
@@ -129,7 +129,7 @@ int coreVersionMinor ()
129129
constexpr
130130
int coreVersionRevision ()
131131
{
132-
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 2);
132+
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2);
133133
}
134134

135135
/*
@@ -139,7 +139,7 @@ int coreVersionRevision ()
139139
constexpr
140140
int coreVersionSubRevision ()
141141
{
142-
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 3);
142+
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3);
143143
}
144144

145145
/*

Diff for: cores/esp8266/umm_malloc/umm_malloc.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -1202,8 +1202,9 @@ static unsigned short int umm_assimilate_down( unsigned short int c, unsigned sh
12021202
}
12031203

12041204
/* ------------------------------------------------------------------------- */
1205-
1206-
void umm_init( void ) {
1205+
/* This function called only one time during OS startup after flash is */
1206+
/* enabled. No need to keep it in IRAM. */
1207+
void ICACHE_FLASH_ATTR umm_init( void ) {
12071208
/* init heap pointer and size, and memset it to 0 */
12081209
umm_heap = (umm_block *)UMM_MALLOC_CFG__HEAP_ADDR;
12091210
umm_numblocks = (UMM_MALLOC_CFG__HEAP_SIZE / sizeof(umm_block));

0 commit comments

Comments
 (0)