@@ -45,10 +45,10 @@ extern void(*__init_array_end)(void);
4545/* Not static, used in Esp.cpp */
4646struct rst_info resetInfo;
4747
48- /* Not static, used in core_esp8266_postmortem.c.
49- * Placed into noinit section because we assign value to this variable
50- * before .bss is zero-filled, and need to preserve the value.
51- */
48+ /* Not static, used in core_esp8266_postmortem.c and other places .
49+ * Placed into noinit section because we assign value to this variable
50+ * before .bss is zero-filled, and need to preserve the value.
51+ */
5252cont_t * g_pcont __attribute__ ((section(" .noinit" )));
5353
5454/* Event queue used by the main (arduino) task */
@@ -57,6 +57,13 @@ static os_event_t s_loop_queue[LOOP_QUEUE_SIZE];
5757/* Used to implement optimistic_yield */
5858static uint32_t s_micros_at_task_start;
5959
60+ /* For ets_intr_lock_nest / ets_intr_unlock_nest
61+ * Max nesting seen by SDK so far is 2.
62+ */
63+ #define ETS_INTR_LOCK_NEST_MAX 7
64+ static uint16_t ets_intr_lock_stack[ETS_INTR_LOCK_NEST_MAX];
65+ static byte ets_intr_lock_stack_ptr = 0 ;
66+
6067
6168extern " C" {
6269 extern const uint32_t __attribute__ ((section(" .ver_number" ))) core_version =
@@ -83,24 +90,36 @@ void preloop_update_frequency()
8390#endif
8491}
8592
93+ extern " C" bool can_yield ()
94+ {
95+ return cont_can_yield (g_pcont);
96+ }
97+
98+ static inline void esp_yield_within_cont () __attribute__((always_inline));
99+ static void esp_yield_within_cont ()
100+ {
101+ cont_yield (g_pcont);
102+ run_scheduled_recurrent_functions ();
103+ }
86104
87105extern " C" void esp_yield ()
88106{
89- if (cont_can_yield (g_pcont )) {
90- cont_yield (g_pcont );
107+ if (can_yield ( )) {
108+ esp_yield_within_cont ( );
91109 }
92110}
93111
94112extern " C" void esp_schedule ()
95113{
114+ // always on CONT stack here
96115 ets_post (LOOP_TASK_PRIORITY, 0 , 0 );
97116}
98117
99118extern " C" void __yield ()
100119{
101- if (cont_can_yield (g_pcont )) {
120+ if (can_yield ( )) {
102121 esp_schedule ();
103- esp_yield ();
122+ esp_yield_within_cont ();
104123 } else {
105124 panic ();
106125 }
@@ -110,12 +129,54 @@ extern "C" void yield(void) __attribute__((weak, alias("__yield")));
110129
111130extern " C" void optimistic_yield (uint32_t interval_us)
112131{
113- if (cont_can_yield (g_pcont ) &&
132+ if (can_yield ( ) &&
114133 (system_get_time () - s_micros_at_task_start) > interval_us) {
115134 yield ();
116135 }
117136}
118137
138+
139+ // Replace ets_intr_(un)lock with nestable versions
140+ extern " C" void IRAM_ATTR ets_intr_lock ()
141+ {
142+ if (ets_intr_lock_stack_ptr < ETS_INTR_LOCK_NEST_MAX) {
143+ ets_intr_lock_stack[ets_intr_lock_stack_ptr++] = xt_rsil (3 );
144+ } else {
145+ xt_rsil (3 );
146+ }
147+ }
148+
149+ extern " C" void IRAM_ATTR ets_intr_unlock ()
150+ {
151+ if (ets_intr_lock_stack_ptr > 0 ) {
152+ xt_wsr_ps (ets_intr_lock_stack[--ets_intr_lock_stack_ptr]);
153+ } else {
154+ xt_rsil (0 );
155+ }
156+ }
157+
158+
159+ // Save / Restore the PS state across the rom ets_post call as the rom code
160+ // does not implement this correctly.
161+ extern " C" bool ets_post_rom (uint8 prio, ETSSignal sig, ETSParam par);
162+
163+ extern " C" bool IRAM_ATTR ets_post (uint8 prio, ETSSignal sig, ETSParam par)
164+ {
165+ uint32_t saved;
166+ asm volatile (" rsr %0,ps" :" =a" (saved));
167+ bool rc = ets_post_rom (prio, sig, par);
168+ xt_wsr_ps (saved);
169+ return rc;
170+ }
171+
172+ extern " C" void __loop_end (void )
173+ {
174+ run_scheduled_functions ();
175+ run_scheduled_recurrent_functions ();
176+ }
177+
178+ extern " C" void loop_end (void ) __attribute__((weak, alias(" __loop_end" )));
179+
119180static void loop_wrapper ()
120181{
121182 static bool setup_done = false ;
@@ -139,101 +200,146 @@ static void loop_task(os_event_t *events)
139200 panic ();
140201 }
141202}
203+ extern " C" {
204+
205+ struct object {
206+ long placeholder[10 ];
207+ };
208+ void __register_frame_info (const void *begin, struct object *ob);
209+ extern char __eh_frame[];
210+ }
142211
143212static void do_global_ctors (void )
144213{
214+ static struct object ob;
215+ __register_frame_info (__eh_frame, &ob);
216+
145217 void (**p)(void ) = &__init_array_end;
146218 while (p != &__init_array_start) {
147219 (*--p)();
148220 }
149221}
150222
223+ extern " C" {
224+ extern void __unhandled_exception (const char *str);
225+
226+ static void __unhandled_exception_cpp ()
227+ {
228+ #ifndef __EXCEPTIONS
229+ abort ();
230+ #else
231+ static bool terminating;
232+ if (terminating) {
233+ abort ();
234+ }
235+ terminating = true ;
236+ /* Use a trick from vterminate.cc to get any std::exception what() */
237+ try {
238+ __throw_exception_again;
239+ } catch (const std::exception& e) {
240+ __unhandled_exception (e.what ());
241+ } catch (...) {
242+ __unhandled_exception (" " );
243+ }
244+ #endif
245+ }
246+
247+ }
248+
151249void init_done ()
152250{
153251 system_set_os_print (1 );
154252 gdb_init ();
253+ std::set_terminate (__unhandled_exception_cpp);
155254 do_global_ctors ();
156255 esp_schedule ();
157256}
158257
159258/* This is the entry point of the application.
160- * It gets called on the default stack, which grows down from the top
161- * of DRAM area.
162- * .bss has not been zeroed out yet, but .data and .rodata are in place.
163- * Cache is not enabled, so only ROM and IRAM functions can be called.
164- * Peripherals (except for SPI0 and UART0) are not initialized.
165- * This function does not return.
166- */
259+ * It gets called on the default stack, which grows down from the top
260+ * of DRAM area.
261+ * .bss has not been zeroed out yet, but .data and .rodata are in place.
262+ * Cache is not enabled, so only ROM and IRAM functions can be called.
263+ * Peripherals (except for SPI0 and UART0) are not initialized.
264+ * This function does not return.
265+ */
167266/*
168- A bit of explanation for this entry point:
169-
170- SYS is the SDK task/context used by the upperlying system to run its
171- administrative tasks (at least WLAN and lwip's receive callbacks and
172- Ticker). NONOS-SDK is designed to run user's non-threaded code in
173- another specific task/context with its own stack in BSS.
174-
175- Some clever fellows found that the SYS stack was a large and quite unused
176- piece of ram that we could use for the user's stack instead of using user's
177- main memory, thus saving around 4KB on ram/heap.
178-
179- A problem arose later, which is that this stack can heavily be used by
180- the SDK for some features. One of these features is WPS. We still don't
181- know if other features are using this, or if this memory is going to be
182- used in future SDK releases.
183-
184- WPS beeing flawed by its poor security, or not beeing used by lots of
185- users, it has been decided that we are still going to use that memory for
186- user's stack and disable the use of WPS, with an option to revert that
187- back at the user's discretion. This selection can be done with the
188- global define NO_EXTRA_4K_HEAP. An option has been added to the board
189- generator script.
190-
191- References:
192- https://github.com/esp8266/Arduino/pull/4553
193- https://github.com/esp8266/Arduino/pull/4622
194- https://github.com/esp8266/Arduino/issues/4779
195- https://github.com/esp8266/Arduino/pull/4889
267+ A bit of explanation for this entry point:
196268
197- */
269+ SYS is the SDK task/context used by the upperlying system to run its
270+ administrative tasks (at least WLAN and lwip's receive callbacks and
271+ Ticker). NONOS-SDK is designed to run user's non-threaded code in
272+ another specific task/context with its own stack in BSS.
198273
199- #ifdef NO_EXTRA_4K_HEAP
200- /* this is the default NONOS-SDK user's heap location */
201- cont_t g_cont __attribute__ ((aligned(16 )));
202- #endif
274+ Some clever fellows found that the SYS stack was a large and quite unused
275+ piece of ram that we could use for the user's stack instead of using user's
276+ main memory, thus saving around 4KB on ram/heap.
203277
204- extern " C" void ICACHE_RAM_ATTR app_entry (void )
205- {
206- #ifdef NO_EXTRA_4K_HEAP
278+ A problem arose later, which is that this stack can heavily be used by
279+ the SDK for some features. One of these features is WPS. We still don't
280+ know if other features are using this, or if this memory is going to be
281+ used in future SDK releases.
207282
208- /* this is the default NONOS-SDK user's heap location */
209- g_pcont = &g_cont;
283+ WPS beeing flawed by its poor security, or not beeing used by lots of
284+ users, it has been decided that we are still going to use that memory for
285+ user's stack and disable the use of WPS.
210286
211- #else
287+ app_entry() jumps to app_entry_custom() defined as "weakref" calling
288+ itself a weak customizable function, allowing to use another one when
289+ this is required (see core_esp8266_app_entry_noextra4k.cpp, used by WPS).
212290
291+ (note: setting app_entry() itself as "weak" is not sufficient and always
292+ ends up with the other "noextra4k" one linked, maybe because it has a
293+ default ENTRY(app_entry) value in linker scripts).
294+
295+ References:
296+ https://github.com/esp8266/Arduino/pull/4553
297+ https://github.com/esp8266/Arduino/pull/4622
298+ https://github.com/esp8266/Arduino/issues/4779
299+ https://github.com/esp8266/Arduino/pull/4889
300+
301+ */
302+
303+ extern " C" void app_entry_redefinable (void ) __attribute__((weak));
304+ extern " C" void app_entry_redefinable (void )
305+ {
213306 /* Allocate continuation context on this SYS stack,
214- and save pointer to it. */
307+ and save pointer to it. */
215308 cont_t s_cont __attribute__ ((aligned (16 )));
216309 g_pcont = &s_cont;
217310
218- #endif
219-
220311 /* Call the entry point of the SDK code. */
221312 call_user_start ();
222313}
223314
315+ static void app_entry_custom (void ) __attribute__((weakref(" app_entry_redefinable" )));
316+
317+ extern " C" void app_entry (void )
318+ {
319+ return app_entry_custom ();
320+ }
321+
322+ extern " C" void preinit (void ) __attribute__((weak));
323+ extern " C" void preinit (void )
324+ {
325+ /* do nothing by default */
326+ }
327+
224328extern " C" void user_init (void )
225329{
226330 struct rst_info *rtc_info_ptr = system_get_rst_info ();
227331 memcpy ((void *)&resetInfo, (void *)rtc_info_ptr, sizeof (resetInfo));
228332
229333 uart_div_modify (0 , UART_CLK_FREQ / (115200 ));
230334
231- init ();
335+ init (); // in core_esp8266_wiring.c, inits hw regs and sdk timer
232336
233337 initVariant ();
234338
235339 cont_init (g_pcont);
236340
341+ preinit (); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable.
342+
237343 ets_task (loop_task,
238344 LOOP_TASK_PRIORITY, s_loop_queue,
239345 LOOP_QUEUE_SIZE);
0 commit comments