Skip to content

Allow byte access to PROGMEM without pgm_read macro #6978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions boards.txt

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions cores/esp8266/core_esp8266_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ extern "C" {
}
#include <core_version.h>
#include "gdb_hooks.h"
#include <core_esp8266_unaligned.h>


#define LOOP_TASK_PRIORITY 1
#define LOOP_QUEUE_SIZE 1
Expand Down Expand Up @@ -320,6 +322,10 @@ 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.

ets_task(loop_task,
Expand Down
90 changes: 90 additions & 0 deletions cores/esp8266/core_esp8266_unaligned.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* 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 <Arduino.h>
#include <core_esp8266_unaligned.h>
#include <esp8266_undocumented.h>
#include <Schedule.h>
#include <debug.h>


#define LOAD_MASK 0x00f00fu
#define L8UI_MATCH 0x000002u
#define L16UI_MATCH 0x001002u
#define L16SI_MATCH 0x009002u

#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;
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:
/* Go to the default handler, we can't help here */
_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;
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);
}
1 change: 1 addition & 0 deletions cores/esp8266/core_esp8266_unaligned.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern void install_unaligned_exception_handler();
39 changes: 39 additions & 0 deletions cores/esp8266/esp8266_undocumented.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
6 changes: 4 additions & 2 deletions platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down
11 changes: 10 additions & 1 deletion tools/boards.txt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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', ''),
])
}

################################################################
Expand Down Expand Up @@ -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 = []
Expand All @@ -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:
Expand Down