From abf6d69af210ec403c200b6e1c653644336c00b8 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 2 Jan 2020 17:28:47 -0800 Subject: [PATCH 1/3] Allow byte access to PROGMEM without pgm_read macro This PR pulls in code from @pvvx's esp8266web server at https://github.com/pvvx/esp8266web (licensed in the public domain) to allow reads of 8 and 16-bit values out of flash without the need for pgm_read_byte/word macros. It installs an exception handler that decodes the faulting instruction and simulates is properly and returns immediately to user code. That said, it is significantly slower (20x?) than using the pgm_read macros properly. --- cores/esp8266/core_esp8266_main.cpp | 4 + cores/esp8266/core_esp8266_unaligned.cpp | 121 +++++++++++++++++++++++ cores/esp8266/core_esp8266_unaligned.h | 11 +++ 3 files changed, 136 insertions(+) create mode 100644 cores/esp8266/core_esp8266_unaligned.cpp create mode 100644 cores/esp8266/core_esp8266_unaligned.h diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 850d9b95a8..40f3521d46 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -34,6 +34,8 @@ extern "C" { } #include #include "gdb_hooks.h" +#include + #define LOOP_TASK_PRIORITY 1 #define LOOP_QUEUE_SIZE 1 @@ -320,6 +322,8 @@ extern "C" void user_init(void) { cont_init(g_pcont); + install_unaligned_exception_handler(); + preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable. ets_task(loop_task, diff --git a/cores/esp8266/core_esp8266_unaligned.cpp b/cores/esp8266/core_esp8266_unaligned.cpp new file mode 100644 index 0000000000..cf00ebbcc2 --- /dev/null +++ b/cores/esp8266/core_esp8266_unaligned.cpp @@ -0,0 +1,121 @@ +/* Unaligned exception handler, allows for byte accesses to PROGMEM to + * succeed without causing a crash. It is still preferred to use the + * xxx_P macros whenever possible, since they are probably 30x faster than + * this exception handler method. + * + * Code taken directly from @pvvx's public domain code in + * https://github.com/pvvx/esp8266web/blob/master/app/sdklib/system/app_main.c + */ + +#include +#include + +extern "C" { + +#define LOAD_MASK 0x00f00fu +#define L8UI_MATCH 0x000002u +#define L16UI_MATCH 0x001002u +#define L16SI_MATCH 0x009002u + +#define EXCCAUSE_LOAD_STORE_ERROR 3 // Unaligned or NULL error + +struct exception_frame +{ + uint32_t epc; + uint32_t ps; + uint32_t sar; + uint32_t unused; + union { + struct { + uint32_t a0; + // note: no a1 here! + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t a8; + uint32_t a9; + uint32_t a10; + uint32_t a11; + uint32_t a12; + uint32_t a13; + uint32_t a14; + uint32_t a15; + }; + uint32_t a_reg[15]; + }; + uint32_t cause; +}; + +extern void _xtos_set_exception_handler(uint32_t reason, void (*fn)(struct exception_frame *ef, uint32_t cause)); +extern void _xtos_unhandled_exception(struct exception_frame *ef, uint32_t cause); + +static ICACHE_RAM_ATTR void read_align_exception_handler(struct exception_frame *ef, uint32_t cause) +{ + /* If this is not EXCCAUSE_LOAD_STORE_ERROR you're doing it wrong! */ + (void)cause; + + uint32_t epc1 = ef->epc; + uint32_t excvaddr; + uint32_t insn; + asm ( + "rsr %0, EXCVADDR;" /* read out the faulting address */ + "movi a4, ~3;" /* prepare a mask for the EPC */ + "and a4, a4, %2;" /* apply mask for 32bit aligned base */ + "l32i a5, a4, 0;" /* load part 1 */ + "l32i a6, a4, 4;" /* load part 2 */ + "ssa8l %2;" /* set up shift register for src op */ + "src %1, a6, a5;" /* right shift to get faulting instruction */ + :"=r"(excvaddr), "=r"(insn) + :"r"(epc1) + :"a4", "a5", "a6" + ); + + uint32_t valmask = 0; + uint32_t what = insn & LOAD_MASK; + + if (what == L8UI_MATCH) + valmask = 0xffu; + else if (what == L16UI_MATCH || what == L16SI_MATCH) + valmask = 0xffffu; + else + { +die: + /* Turns out we couldn't fix this, trigger a system break instead + * and hang if the break doesn't get handled. This is effectively + * what would happen if the default handler was installed. */ + _xtos_unhandled_exception(ef, cause); + asm ("break 1, 1"); + while (1) {} + } + + /* Load, shift and mask down to correct size */ + uint32_t val = (*(uint32_t *)(excvaddr & ~0x3)); + val >>= (excvaddr & 0x3) * 8; + val &= valmask; + + /* Sign-extend for L16SI, if applicable */ + if (what == L16SI_MATCH && (val & 0x8000)) + val |= 0xffff0000; + + int regno = (insn & 0x0000f0u) >> 4; + if (regno == 1) + goto die; /* we can't support loading into a1, just die */ + else if (regno != 0) + --regno; /* account for skipped a1 in exception_frame */ + + ef->a_reg[regno] = val; /* carry out the load */ + ef->epc += 3; /* resume at following instruction */ +} + + + +void install_unaligned_exception_handler() +{ + _xtos_set_exception_handler(EXCCAUSE_LOAD_STORE_ERROR, read_align_exception_handler); +} + + +}; diff --git a/cores/esp8266/core_esp8266_unaligned.h b/cores/esp8266/core_esp8266_unaligned.h new file mode 100644 index 0000000000..f898501883 --- /dev/null +++ b/cores/esp8266/core_esp8266_unaligned.h @@ -0,0 +1,11 @@ +#ifdef __cplusplus +extern "C" { +#endif + +extern void install_unaligned_exception_handler(); + + +#ifdef __cplusplus +}; +#endif + From 88d9fc02cc5223403099250ea34f4243e4cadc57 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 3 Jan 2020 08:14:27 -0800 Subject: [PATCH 2/3] Refactor and minimize code Move the ROM defintions into esp8266_undefined.h, and add ifdef bracketing around the whole header (it's included multiple times). Remove some unneeded, left-over code and comments. Use __asm to make compatible with --std=c++17 Requires 162 bytes of IRAM for the handler. --- cores/esp8266/core_esp8266_unaligned.cpp | 50 +++--------------------- cores/esp8266/esp8266_undocumented.h | 39 ++++++++++++++++++ 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/cores/esp8266/core_esp8266_unaligned.cpp b/cores/esp8266/core_esp8266_unaligned.cpp index cf00ebbcc2..d495d40316 100644 --- a/cores/esp8266/core_esp8266_unaligned.cpp +++ b/cores/esp8266/core_esp8266_unaligned.cpp @@ -9,6 +9,7 @@ #include #include +#include extern "C" { @@ -17,50 +18,14 @@ extern "C" { #define L16UI_MATCH 0x001002u #define L16SI_MATCH 0x009002u -#define EXCCAUSE_LOAD_STORE_ERROR 3 // Unaligned or NULL error +#define EXCCAUSE_LOAD_STORE_ERROR 3 // Unaligned read/write error -struct exception_frame +static ICACHE_RAM_ATTR void read_align_exception_handler(struct __exception_frame *ef, uint32_t cause) { - uint32_t epc; - uint32_t ps; - uint32_t sar; - uint32_t unused; - union { - struct { - uint32_t a0; - // note: no a1 here! - uint32_t a2; - uint32_t a3; - uint32_t a4; - uint32_t a5; - uint32_t a6; - uint32_t a7; - uint32_t a8; - uint32_t a9; - uint32_t a10; - uint32_t a11; - uint32_t a12; - uint32_t a13; - uint32_t a14; - uint32_t a15; - }; - uint32_t a_reg[15]; - }; - uint32_t cause; -}; - -extern void _xtos_set_exception_handler(uint32_t reason, void (*fn)(struct exception_frame *ef, uint32_t cause)); -extern void _xtos_unhandled_exception(struct exception_frame *ef, uint32_t cause); - -static ICACHE_RAM_ATTR void read_align_exception_handler(struct exception_frame *ef, uint32_t cause) -{ - /* If this is not EXCCAUSE_LOAD_STORE_ERROR you're doing it wrong! */ - (void)cause; - uint32_t epc1 = ef->epc; uint32_t excvaddr; uint32_t insn; - asm ( + __asm ( "rsr %0, EXCVADDR;" /* read out the faulting address */ "movi a4, ~3;" /* prepare a mask for the EPC */ "and a4, a4, %2;" /* apply mask for 32bit aligned base */ @@ -83,12 +48,8 @@ static ICACHE_RAM_ATTR void read_align_exception_handler(struct exception_frame else { die: - /* Turns out we couldn't fix this, trigger a system break instead - * and hang if the break doesn't get handled. This is effectively - * what would happen if the default handler was installed. */ + /* Go to the default handler, we can't help here */ _xtos_unhandled_exception(ef, cause); - asm ("break 1, 1"); - while (1) {} } /* Load, shift and mask down to correct size */ @@ -111,7 +72,6 @@ static ICACHE_RAM_ATTR void read_align_exception_handler(struct exception_frame } - void install_unaligned_exception_handler() { _xtos_set_exception_handler(EXCCAUSE_LOAD_STORE_ERROR, read_align_exception_handler); diff --git a/cores/esp8266/esp8266_undocumented.h b/cores/esp8266/esp8266_undocumented.h index 22216d962a..31f872c399 100644 --- a/cores/esp8266/esp8266_undocumented.h +++ b/cores/esp8266/esp8266_undocumented.h @@ -1,5 +1,8 @@ // ROM and blob calls without official headers available +#ifndef __ESP8266_UNDOCUMENTED_H +#define __ESP8266_UNDOCUMENTED_H + #ifdef __cplusplus extern "C" { #endif @@ -34,6 +37,42 @@ extern int ets_uart_printf(const char *format, ...) __attribute__ ((format (prin extern void ets_delay_us(uint32_t us); +/* The Xtensa OS code in ROM for handling hardware exceptions */ +struct __exception_frame +{ + uint32_t epc; + uint32_t ps; + uint32_t sar; + uint32_t unused; + union { + struct { + uint32_t a0; + // note: no a1 here! + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t a8; + uint32_t a9; + uint32_t a10; + uint32_t a11; + uint32_t a12; + uint32_t a13; + uint32_t a14; + uint32_t a15; + }; + uint32_t a_reg[15]; + }; + uint32_t cause; +}; + +extern void _xtos_set_exception_handler(uint32_t reason, void (*fn)(struct __exception_frame *ef, uint32_t cause)); +extern void _xtos_unhandled_exception(struct __exception_frame *ef, uint32_t cause); + #ifdef __cplusplus }; #endif + +#endif From 5394e7150bf2b36c89bfaee06bf27488f99f82cc Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 6 Jan 2020 21:00:56 -0800 Subject: [PATCH 3/3] Add menu option to disable unaligned handler, warn Adds a menu option to disable the handler (default is enabled for beginning users). Add a single debug printout when it is invoked via a scheduled function warning that performance may suffer. --- boards.txt | 133 +++++++++++++++++++++++ cores/esp8266/core_esp8266_main.cpp | 2 + cores/esp8266/core_esp8266_unaligned.cpp | 17 ++- cores/esp8266/core_esp8266_unaligned.h | 10 -- platform.txt | 6 +- tools/boards.txt.py | 11 +- 6 files changed, 162 insertions(+), 17 deletions(-) diff --git a/boards.txt b/boards.txt index da0bf54d3f..376bbf639b 100644 --- a/boards.txt +++ b/boards.txt @@ -22,6 +22,7 @@ menu.exception=Exceptions menu.wipe=Erase Flash menu.sdk=Espressif FW menu.ssl=SSL Support +menu.unaligned=Unaligned Accesses ############################################################## generic.name=Generic ESP8266 Module @@ -61,6 +62,10 @@ generic.menu.ssl.all=All SSL ciphers (most compatible) generic.menu.ssl.all.build.sslflags= generic.menu.ssl.basic=Basic SSL ciphers (lower ROM use) generic.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +generic.menu.unaligned.safe=Allow byte and word access to PROGMEM +generic.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +generic.menu.unaligned.fast=Require pgm_read macros for PROGMEM +generic.menu.unaligned.fast.build.unalignedflags= generic.menu.ResetMethod.nodemcu=dtr (aka nodemcu) generic.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset generic.menu.ResetMethod.ck=no dtr (aka ck) @@ -536,6 +541,10 @@ esp8285.menu.ssl.all=All SSL ciphers (most compatible) esp8285.menu.ssl.all.build.sslflags= esp8285.menu.ssl.basic=Basic SSL ciphers (lower ROM use) esp8285.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +esp8285.menu.unaligned.safe=Allow byte and word access to PROGMEM +esp8285.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +esp8285.menu.unaligned.fast=Require pgm_read macros for PROGMEM +esp8285.menu.unaligned.fast.build.unalignedflags= esp8285.menu.ResetMethod.nodemcu=dtr (aka nodemcu) esp8285.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset esp8285.menu.ResetMethod.ck=no dtr (aka ck) @@ -820,6 +829,10 @@ espduino.menu.ssl.all=All SSL ciphers (most compatible) espduino.menu.ssl.all.build.sslflags= espduino.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espduino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espduino.menu.unaligned.safe=Allow byte and word access to PROGMEM +espduino.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espduino.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espduino.menu.unaligned.fast.build.unalignedflags= espduino.build.flash_mode=dio espduino.build.flash_flags=-DFLASHMODE_DIO espduino.build.flash_freq=40 @@ -1012,6 +1025,10 @@ huzzah.menu.ssl.all=All SSL ciphers (most compatible) huzzah.menu.ssl.all.build.sslflags= huzzah.menu.ssl.basic=Basic SSL ciphers (lower ROM use) huzzah.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +huzzah.menu.unaligned.safe=Allow byte and word access to PROGMEM +huzzah.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +huzzah.menu.unaligned.fast=Require pgm_read macros for PROGMEM +huzzah.menu.unaligned.fast.build.unalignedflags= huzzah.upload.resetmethod=--before default_reset --after hard_reset huzzah.build.flash_mode=qio huzzah.build.flash_flags=-DFLASHMODE_QIO @@ -1205,6 +1222,10 @@ inventone.menu.ssl.all=All SSL ciphers (most compatible) inventone.menu.ssl.all.build.sslflags= inventone.menu.ssl.basic=Basic SSL ciphers (lower ROM use) inventone.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +inventone.menu.unaligned.safe=Allow byte and word access to PROGMEM +inventone.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +inventone.menu.unaligned.fast=Require pgm_read macros for PROGMEM +inventone.menu.unaligned.fast.build.unalignedflags= inventone.upload.resetmethod=--before default_reset --after hard_reset inventone.build.flash_mode=dio inventone.build.flash_flags=-DFLASHMODE_DIO @@ -1398,6 +1419,10 @@ cw01.menu.ssl.all=All SSL ciphers (most compatible) cw01.menu.ssl.all.build.sslflags= cw01.menu.ssl.basic=Basic SSL ciphers (lower ROM use) cw01.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +cw01.menu.unaligned.safe=Allow byte and word access to PROGMEM +cw01.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +cw01.menu.unaligned.fast=Require pgm_read macros for PROGMEM +cw01.menu.unaligned.fast.build.unalignedflags= cw01.upload.resetmethod=--before default_reset --after hard_reset cw01.menu.CrystalFreq.26=26 MHz cw01.menu.CrystalFreq.40=40 MHz @@ -1594,6 +1619,10 @@ espresso_lite_v1.menu.ssl.all=All SSL ciphers (most compatible) espresso_lite_v1.menu.ssl.all.build.sslflags= espresso_lite_v1.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espresso_lite_v1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espresso_lite_v1.menu.unaligned.safe=Allow byte and word access to PROGMEM +espresso_lite_v1.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espresso_lite_v1.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espresso_lite_v1.menu.unaligned.fast.build.unalignedflags= espresso_lite_v1.build.flash_mode=dio espresso_lite_v1.build.flash_flags=-DFLASHMODE_DIO espresso_lite_v1.build.flash_freq=40 @@ -1790,6 +1819,10 @@ espresso_lite_v2.menu.ssl.all=All SSL ciphers (most compatible) espresso_lite_v2.menu.ssl.all.build.sslflags= espresso_lite_v2.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espresso_lite_v2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espresso_lite_v2.menu.unaligned.safe=Allow byte and word access to PROGMEM +espresso_lite_v2.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espresso_lite_v2.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espresso_lite_v2.menu.unaligned.fast.build.unalignedflags= espresso_lite_v2.build.flash_mode=dio espresso_lite_v2.build.flash_flags=-DFLASHMODE_DIO espresso_lite_v2.build.flash_freq=40 @@ -1986,6 +2019,10 @@ phoenix_v1.menu.ssl.all=All SSL ciphers (most compatible) phoenix_v1.menu.ssl.all.build.sslflags= phoenix_v1.menu.ssl.basic=Basic SSL ciphers (lower ROM use) phoenix_v1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +phoenix_v1.menu.unaligned.safe=Allow byte and word access to PROGMEM +phoenix_v1.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +phoenix_v1.menu.unaligned.fast=Require pgm_read macros for PROGMEM +phoenix_v1.menu.unaligned.fast.build.unalignedflags= phoenix_v1.build.flash_mode=dio phoenix_v1.build.flash_flags=-DFLASHMODE_DIO phoenix_v1.build.flash_freq=40 @@ -2182,6 +2219,10 @@ phoenix_v2.menu.ssl.all=All SSL ciphers (most compatible) phoenix_v2.menu.ssl.all.build.sslflags= phoenix_v2.menu.ssl.basic=Basic SSL ciphers (lower ROM use) phoenix_v2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +phoenix_v2.menu.unaligned.safe=Allow byte and word access to PROGMEM +phoenix_v2.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +phoenix_v2.menu.unaligned.fast=Require pgm_read macros for PROGMEM +phoenix_v2.menu.unaligned.fast.build.unalignedflags= phoenix_v2.build.flash_mode=dio phoenix_v2.build.flash_flags=-DFLASHMODE_DIO phoenix_v2.build.flash_freq=40 @@ -2378,6 +2419,10 @@ nodemcu.menu.ssl.all=All SSL ciphers (most compatible) nodemcu.menu.ssl.all.build.sslflags= nodemcu.menu.ssl.basic=Basic SSL ciphers (lower ROM use) nodemcu.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +nodemcu.menu.unaligned.safe=Allow byte and word access to PROGMEM +nodemcu.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +nodemcu.menu.unaligned.fast=Require pgm_read macros for PROGMEM +nodemcu.menu.unaligned.fast.build.unalignedflags= nodemcu.upload.resetmethod=--before default_reset --after hard_reset nodemcu.build.flash_mode=qio nodemcu.build.flash_flags=-DFLASHMODE_QIO @@ -2571,6 +2616,10 @@ nodemcuv2.menu.ssl.all=All SSL ciphers (most compatible) nodemcuv2.menu.ssl.all.build.sslflags= nodemcuv2.menu.ssl.basic=Basic SSL ciphers (lower ROM use) nodemcuv2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +nodemcuv2.menu.unaligned.safe=Allow byte and word access to PROGMEM +nodemcuv2.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +nodemcuv2.menu.unaligned.fast=Require pgm_read macros for PROGMEM +nodemcuv2.menu.unaligned.fast.build.unalignedflags= nodemcuv2.upload.resetmethod=--before default_reset --after hard_reset nodemcuv2.build.flash_mode=dio nodemcuv2.build.flash_flags=-DFLASHMODE_DIO @@ -2768,6 +2817,10 @@ modwifi.menu.ssl.all=All SSL ciphers (most compatible) modwifi.menu.ssl.all.build.sslflags= modwifi.menu.ssl.basic=Basic SSL ciphers (lower ROM use) modwifi.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +modwifi.menu.unaligned.safe=Allow byte and word access to PROGMEM +modwifi.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +modwifi.menu.unaligned.fast=Require pgm_read macros for PROGMEM +modwifi.menu.unaligned.fast.build.unalignedflags= modwifi.upload.resetmethod=--before no_reset --after soft_reset modwifi.build.flash_mode=qio modwifi.build.flash_flags=-DFLASHMODE_QIO @@ -2981,6 +3034,10 @@ thing.menu.ssl.all=All SSL ciphers (most compatible) thing.menu.ssl.all.build.sslflags= thing.menu.ssl.basic=Basic SSL ciphers (lower ROM use) thing.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +thing.menu.unaligned.safe=Allow byte and word access to PROGMEM +thing.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +thing.menu.unaligned.fast=Require pgm_read macros for PROGMEM +thing.menu.unaligned.fast.build.unalignedflags= thing.upload.resetmethod=--before no_reset --after soft_reset thing.build.flash_mode=qio thing.build.flash_flags=-DFLASHMODE_QIO @@ -3174,6 +3231,10 @@ thingdev.menu.ssl.all=All SSL ciphers (most compatible) thingdev.menu.ssl.all.build.sslflags= thingdev.menu.ssl.basic=Basic SSL ciphers (lower ROM use) thingdev.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +thingdev.menu.unaligned.safe=Allow byte and word access to PROGMEM +thingdev.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +thingdev.menu.unaligned.fast=Require pgm_read macros for PROGMEM +thingdev.menu.unaligned.fast.build.unalignedflags= thingdev.upload.resetmethod=--before default_reset --after hard_reset thingdev.build.flash_mode=dio thingdev.build.flash_flags=-DFLASHMODE_DIO @@ -3367,6 +3428,10 @@ blynk.menu.ssl.all=All SSL ciphers (most compatible) blynk.menu.ssl.all.build.sslflags= blynk.menu.ssl.basic=Basic SSL ciphers (lower ROM use) blynk.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +blynk.menu.unaligned.safe=Allow byte and word access to PROGMEM +blynk.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +blynk.menu.unaligned.fast=Require pgm_read macros for PROGMEM +blynk.menu.unaligned.fast.build.unalignedflags= blynk.upload.resetmethod=--before default_reset --after hard_reset blynk.build.flash_mode=qio blynk.build.flash_flags=-DFLASHMODE_QIO @@ -3560,6 +3625,10 @@ esp210.menu.ssl.all=All SSL ciphers (most compatible) esp210.menu.ssl.all.build.sslflags= esp210.menu.ssl.basic=Basic SSL ciphers (lower ROM use) esp210.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +esp210.menu.unaligned.safe=Allow byte and word access to PROGMEM +esp210.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +esp210.menu.unaligned.fast=Require pgm_read macros for PROGMEM +esp210.menu.unaligned.fast.build.unalignedflags= esp210.upload.resetmethod=--before no_reset --after soft_reset esp210.build.flash_mode=qio esp210.build.flash_flags=-DFLASHMODE_QIO @@ -3753,6 +3822,10 @@ d1_mini.menu.ssl.all=All SSL ciphers (most compatible) d1_mini.menu.ssl.all.build.sslflags= d1_mini.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1_mini.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +d1_mini.menu.unaligned.safe=Allow byte and word access to PROGMEM +d1_mini.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +d1_mini.menu.unaligned.fast=Require pgm_read macros for PROGMEM +d1_mini.menu.unaligned.fast.build.unalignedflags= d1_mini.upload.resetmethod=--before default_reset --after hard_reset d1_mini.build.flash_mode=dio d1_mini.build.flash_flags=-DFLASHMODE_DIO @@ -3946,6 +4019,10 @@ d1_mini_pro.menu.ssl.all=All SSL ciphers (most compatible) d1_mini_pro.menu.ssl.all.build.sslflags= d1_mini_pro.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1_mini_pro.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +d1_mini_pro.menu.unaligned.safe=Allow byte and word access to PROGMEM +d1_mini_pro.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +d1_mini_pro.menu.unaligned.fast=Require pgm_read macros for PROGMEM +d1_mini_pro.menu.unaligned.fast.build.unalignedflags= d1_mini_pro.upload.resetmethod=--before default_reset --after hard_reset d1_mini_pro.build.flash_mode=dio d1_mini_pro.build.flash_flags=-DFLASHMODE_DIO @@ -4122,6 +4199,10 @@ d1_mini_lite.menu.ssl.all=All SSL ciphers (most compatible) d1_mini_lite.menu.ssl.all.build.sslflags= d1_mini_lite.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1_mini_lite.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +d1_mini_lite.menu.unaligned.safe=Allow byte and word access to PROGMEM +d1_mini_lite.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +d1_mini_lite.menu.unaligned.fast=Require pgm_read macros for PROGMEM +d1_mini_lite.menu.unaligned.fast.build.unalignedflags= d1_mini_lite.upload.resetmethod=--before default_reset --after hard_reset d1_mini_lite.build.flash_mode=dout d1_mini_lite.build.flash_flags=-DFLASHMODE_DOUT @@ -4355,6 +4436,10 @@ d1.menu.ssl.all=All SSL ciphers (most compatible) d1.menu.ssl.all.build.sslflags= d1.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +d1.menu.unaligned.safe=Allow byte and word access to PROGMEM +d1.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +d1.menu.unaligned.fast=Require pgm_read macros for PROGMEM +d1.menu.unaligned.fast.build.unalignedflags= d1.upload.resetmethod=--before default_reset --after hard_reset d1.build.flash_mode=dio d1.build.flash_flags=-DFLASHMODE_DIO @@ -4548,6 +4633,10 @@ espino.menu.ssl.all=All SSL ciphers (most compatible) espino.menu.ssl.all.build.sslflags= espino.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espino.menu.unaligned.safe=Allow byte and word access to PROGMEM +espino.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espino.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espino.menu.unaligned.fast.build.unalignedflags= espino.menu.ResetMethod.nodemcu=dtr (aka nodemcu) espino.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset espino.menu.ResetMethod.ck=no dtr (aka ck) @@ -4744,6 +4833,10 @@ espinotee.menu.ssl.all=All SSL ciphers (most compatible) espinotee.menu.ssl.all.build.sslflags= espinotee.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espinotee.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espinotee.menu.unaligned.safe=Allow byte and word access to PROGMEM +espinotee.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espinotee.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espinotee.menu.unaligned.fast.build.unalignedflags= espinotee.upload.resetmethod=--before default_reset --after hard_reset espinotee.build.flash_mode=qio espinotee.build.flash_flags=-DFLASHMODE_QIO @@ -4954,6 +5047,10 @@ wifinfo.menu.ssl.all=All SSL ciphers (most compatible) wifinfo.menu.ssl.all.build.sslflags= wifinfo.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wifinfo.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +wifinfo.menu.unaligned.safe=Allow byte and word access to PROGMEM +wifinfo.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +wifinfo.menu.unaligned.fast=Require pgm_read macros for PROGMEM +wifinfo.menu.unaligned.fast.build.unalignedflags= wifinfo.upload.resetmethod=--before default_reset --after hard_reset wifinfo.build.flash_mode=qio wifinfo.build.flash_flags=-DFLASHMODE_QIO @@ -5206,6 +5303,10 @@ arduino-esp8266.menu.ssl.all=All SSL ciphers (most compatible) arduino-esp8266.menu.ssl.all.build.sslflags= arduino-esp8266.menu.ssl.basic=Basic SSL ciphers (lower ROM use) arduino-esp8266.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +arduino-esp8266.menu.unaligned.safe=Allow byte and word access to PROGMEM +arduino-esp8266.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +arduino-esp8266.menu.unaligned.fast=Require pgm_read macros for PROGMEM +arduino-esp8266.menu.unaligned.fast.build.unalignedflags= arduino-esp8266.upload.resetmethod=--before no_reset --after soft_reset arduino-esp8266.build.flash_mode=qio arduino-esp8266.build.flash_flags=-DFLASHMODE_QIO @@ -5400,6 +5501,10 @@ gen4iod.menu.ssl.all=All SSL ciphers (most compatible) gen4iod.menu.ssl.all.build.sslflags= gen4iod.menu.ssl.basic=Basic SSL ciphers (lower ROM use) gen4iod.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +gen4iod.menu.unaligned.safe=Allow byte and word access to PROGMEM +gen4iod.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +gen4iod.menu.unaligned.fast=Require pgm_read macros for PROGMEM +gen4iod.menu.unaligned.fast.build.unalignedflags= gen4iod.upload.resetmethod=--before default_reset --after hard_reset gen4iod.build.flash_mode=dio gen4iod.build.flash_flags=-DFLASHMODE_DIO @@ -5594,6 +5699,10 @@ oak.menu.ssl.all=All SSL ciphers (most compatible) oak.menu.ssl.all.build.sslflags= oak.menu.ssl.basic=Basic SSL ciphers (lower ROM use) oak.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +oak.menu.unaligned.safe=Allow byte and word access to PROGMEM +oak.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +oak.menu.unaligned.fast=Require pgm_read macros for PROGMEM +oak.menu.unaligned.fast.build.unalignedflags= oak.upload.resetmethod=--before no_reset --after soft_reset oak.build.flash_mode=dio oak.build.flash_flags=-DFLASHMODE_DIO @@ -5787,6 +5896,10 @@ wifiduino.menu.ssl.all=All SSL ciphers (most compatible) wifiduino.menu.ssl.all.build.sslflags= wifiduino.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wifiduino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +wifiduino.menu.unaligned.safe=Allow byte and word access to PROGMEM +wifiduino.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +wifiduino.menu.unaligned.fast=Require pgm_read macros for PROGMEM +wifiduino.menu.unaligned.fast.build.unalignedflags= wifiduino.upload.resetmethod=--before default_reset --after hard_reset wifiduino.build.flash_mode=dio wifiduino.build.flash_flags=-DFLASHMODE_DIO @@ -5980,6 +6093,10 @@ wifi_slot.menu.ssl.all=All SSL ciphers (most compatible) wifi_slot.menu.ssl.all.build.sslflags= wifi_slot.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wifi_slot.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +wifi_slot.menu.unaligned.safe=Allow byte and word access to PROGMEM +wifi_slot.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +wifi_slot.menu.unaligned.fast=Require pgm_read macros for PROGMEM +wifi_slot.menu.unaligned.fast.build.unalignedflags= wifi_slot.upload.resetmethod=--before default_reset --after hard_reset wifi_slot.menu.FlashFreq.40=40MHz wifi_slot.menu.FlashFreq.40.build.flash_freq=40 @@ -6287,6 +6404,10 @@ wiolink.menu.ssl.all=All SSL ciphers (most compatible) wiolink.menu.ssl.all.build.sslflags= wiolink.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wiolink.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +wiolink.menu.unaligned.safe=Allow byte and word access to PROGMEM +wiolink.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +wiolink.menu.unaligned.fast=Require pgm_read macros for PROGMEM +wiolink.menu.unaligned.fast.build.unalignedflags= wiolink.upload.resetmethod=--before default_reset --after hard_reset wiolink.build.flash_mode=qio wiolink.build.flash_flags=-DFLASHMODE_QIO @@ -6480,6 +6601,10 @@ espectro.menu.ssl.all=All SSL ciphers (most compatible) espectro.menu.ssl.all.build.sslflags= espectro.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espectro.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espectro.menu.unaligned.safe=Allow byte and word access to PROGMEM +espectro.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espectro.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espectro.menu.unaligned.fast.build.unalignedflags= espectro.upload.resetmethod=--before default_reset --after hard_reset espectro.build.flash_mode=dio espectro.build.flash_flags=-DFLASHMODE_DIO @@ -6683,6 +6808,10 @@ sonoff.menu.ssl.all=All SSL ciphers (most compatible) sonoff.menu.ssl.all.build.sslflags= sonoff.menu.ssl.basic=Basic SSL ciphers (lower ROM use) sonoff.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +sonoff.menu.unaligned.safe=Allow byte and word access to PROGMEM +sonoff.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +sonoff.menu.unaligned.fast=Require pgm_read macros for PROGMEM +sonoff.menu.unaligned.fast.build.unalignedflags= sonoff.upload.resetmethod=--before no_reset --after soft_reset sonoff.build.flash_mode=dout sonoff.build.flash_flags=-DFLASHMODE_DOUT @@ -6917,6 +7046,10 @@ espmxdevkit.menu.ssl.all=All SSL ciphers (most compatible) espmxdevkit.menu.ssl.all.build.sslflags= espmxdevkit.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espmxdevkit.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espmxdevkit.menu.unaligned.safe=Allow byte and word access to PROGMEM +espmxdevkit.menu.unaligned.safe.build.unalignedflags=-DUNALIGNED_HANDLER +espmxdevkit.menu.unaligned.fast=Require pgm_read macros for PROGMEM +espmxdevkit.menu.unaligned.fast.build.unalignedflags= espmxdevkit.upload.resetmethod=--before default_reset --after hard_reset espmxdevkit.build.flash_mode=dout espmxdevkit.build.flash_flags=-DFLASHMODE_DOUT diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 40f3521d46..34a3da0c1f 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -322,7 +322,9 @@ extern "C" void user_init(void) { cont_init(g_pcont); +#ifdef UNALIGNED_HANDLER install_unaligned_exception_handler(); +#endif preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable. diff --git a/cores/esp8266/core_esp8266_unaligned.cpp b/cores/esp8266/core_esp8266_unaligned.cpp index d495d40316..351b2c1944 100644 --- a/cores/esp8266/core_esp8266_unaligned.cpp +++ b/cores/esp8266/core_esp8266_unaligned.cpp @@ -10,8 +10,9 @@ #include #include #include +#include +#include -extern "C" { #define LOAD_MASK 0x00f00fu #define L8UI_MATCH 0x000002u @@ -20,6 +21,12 @@ extern "C" { #define EXCCAUSE_LOAD_STORE_ERROR 3 // Unaligned read/write error +static bool fired = false; +static void warning(void) +{ + DEBUGV("WARNING: The unaligned hander has been invoked and performance may suffer.\n"); +} + static ICACHE_RAM_ATTR void read_align_exception_handler(struct __exception_frame *ef, uint32_t cause) { uint32_t epc1 = ef->epc; @@ -52,6 +59,11 @@ static ICACHE_RAM_ATTR void read_align_exception_handler(struct __exception_fram _xtos_unhandled_exception(ef, cause); } + if (!fired) { + fired = true; + schedule_function(warning); + } + /* Load, shift and mask down to correct size */ uint32_t val = (*(uint32_t *)(excvaddr & ~0x3)); val >>= (excvaddr & 0x3) * 8; @@ -76,6 +88,3 @@ void install_unaligned_exception_handler() { _xtos_set_exception_handler(EXCCAUSE_LOAD_STORE_ERROR, read_align_exception_handler); } - - -}; diff --git a/cores/esp8266/core_esp8266_unaligned.h b/cores/esp8266/core_esp8266_unaligned.h index f898501883..f38c731194 100644 --- a/cores/esp8266/core_esp8266_unaligned.h +++ b/cores/esp8266/core_esp8266_unaligned.h @@ -1,11 +1 @@ -#ifdef __cplusplus -extern "C" { -#endif - extern void install_unaligned_exception_handler(); - - -#ifdef __cplusplus -}; -#endif - diff --git a/platform.txt b/platform.txt index 678be1ba9d..21e5972842 100644 --- a/platform.txt +++ b/platform.txt @@ -33,6 +33,8 @@ build.vtable_flags=-DVTABLES_IN_FLASH build.sslflags= +build.unalignedflags= + build.exception_flags=-fno-exceptions build.stdcpp_lib=-lstdc++ build.stdcpp_level=-std=gnu++11 @@ -53,7 +55,7 @@ compiler.libc.path={runtime.platform.path}/tools/sdk/libc/xtensa-lx106-elf compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/{build.lwip_include}" "-I{compiler.libc.path}/include" "-I{build.path}/core" compiler.c.cmd=xtensa-lx106-elf-gcc -compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} +compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} {build.unalignedflags} compiler.S.cmd=xtensa-lx106-elf-gcc compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls @@ -64,7 +66,7 @@ compiler.c.elf.cmd=xtensa-lx106-elf-gcc compiler.c.elf.libs=-lhal -lphy -lpp -lnet80211 {build.lwip_lib} -lwpa -lcrypto -lmain -lwps -lbearssl -laxtls -lespnow -lsmartconfig -lairkiss -lwpa2 {build.stdcpp_lib} -lm -lc -lgcc compiler.cpp.cmd=xtensa-lx106-elf-g++ -compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 {build.stdcpp_level} -MMD -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} +compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 {build.stdcpp_level} -MMD -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} {build.unalignedflags} compiler.as.cmd=xtensa-lx106-elf-as diff --git a/tools/boards.txt.py b/tools/boards.txt.py index 8fbffceb4f..3d490291b5 100755 --- a/tools/boards.txt.py +++ b/tools/boards.txt.py @@ -1186,6 +1186,14 @@ ( '.menu.ssl.basic.build.sslflags', '-DBEARSSL_SSL_BASIC'), ]), + ######################## Unaligned exception handler + + 'unaligned_menu': collections.OrderedDict([ + ('.menu.unaligned.safe', 'Allow byte and word access to PROGMEM' ), + ('.menu.unaligned.safe.build.unalignedflags', '-DUNALIGNED_HANDLER'), + ('.menu.unaligned.fast', 'Require pgm_read macros for PROGMEM' ), + ('.menu.unaligned.fast.build.unalignedflags', ''), + ]) } ################################################################ @@ -1546,6 +1554,7 @@ def all_boards (): print('menu.wipe=Erase Flash') print('menu.sdk=Espressif FW') print('menu.ssl=SSL Support') + print('menu.unaligned=Unaligned Accesses') print('') missingboards = [] @@ -1564,7 +1573,7 @@ def all_boards (): print(id + optname + '=' + board['opts'][optname]) # macros - macrolist = [ 'defaults', 'cpufreq_menu', 'vtable_menu', 'exception_menu', 'ssl_cipher_menu' ] + macrolist = [ 'defaults', 'cpufreq_menu', 'vtable_menu', 'exception_menu', 'ssl_cipher_menu', 'unaligned_menu' ] if 'macro' in board: macrolist += board['macro'] if lwip == 2: