From 4a15c6268939f2ffa4903513a2008e4f265661df Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 9 Apr 2020 17:20:01 -0700 Subject: [PATCH 1/4] mp_port_fun_table: port-independent code to support port-specific functions in native modules --- docs/develop/natmod.rst | 38 ++++++++++++++---- py/dynruntime.mk | 7 +++- py/mkenv.mk | 4 +- py/persistentcode.c | 22 ++++++++++ tools/mpy_ld.py | 89 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 138 insertions(+), 22 deletions(-) diff --git a/docs/develop/natmod.rst b/docs/develop/natmod.rst index 251f21e9f4d11..be35e1d49dbe2 100644 --- a/docs/develop/natmod.rst +++ b/docs/develop/natmod.rst @@ -68,14 +68,36 @@ So, if your C code has writable data, make sure the data is defined globally, without an initialiser, and only written to within functions. Linker limitation: the native module is not linked against the symbol table of the -full MicroPython firmware. Rather, it is linked against an explicit table of exported -symbols found in ``mp_fun_table`` (in ``py/nativeglue.h``), that is fixed at firmware -build time. It is thus not possible to simply call some arbitrary HAL/OS/RTOS/system -function, for example. - -New symbols can be added to the end of the table and the firmware rebuilt. -The symbols also need to be added to ``tools/mpy_ld.py``'s ``fun_table`` dict in the -same location. This allows ``mpy_ld.py`` to be able to pick the new symbols up and +full MicroPython firmware. +It is thus not possible to simply call some arbitrary HAL/OS/RTOS/system +function. However, there are two limited linking mechanisms available: +via the ``mp_fun_table`` and on some ports (initially esp32 only) the +``mp_port_fun_table``. + +The ``mp_fun_table`` is the same on all ports and is defined in ``py/nativeglue.h``. +It contains references to close to a hundred functions in MicroPython's core +that can be used by native code. The functions are defined as a set of macros +that turn what looks like a direct call (e.g. ``mp_printf(...)``) into +indirect calls via ``mp_fun_table`` (e.g. ``(*mp_fun_table[72])(...)``). + +The ``mp_port_fun_table`` is a table available on some ports that +exposes additional port-specific functions, typically ones coming from large +RTOS or networking libraries, such as ESP-IDF in the esp32 case. +The ``mp_port_fun_table`` may also expose some commonly used functions from +the standard C library (libc). +The ``mp_port_fun_table`` contains the addresses of the exposed functions +and references in the native modules are "fixed-up" as part of the dynamic +linking process. +If a native module calls a function that does not exist (for example +due to varying sets of libraries built into the firmware) the call +will raise a ``RunTimeError``. +A sample native module using the ``mp_port_fun_table`` can be found in +``examples/natmod/esp32-heap``. + +New symbols can be added to the end of either table and the firmware rebuilt. +In the case of the ``mp_fun_table`` the symbols also need to be added to +``tools/mpy_ld.py``'s ``fun_table`` dict in the same location. +This allows ``mpy_ld.py`` to be able to pick the new symbols up and provide relocations for them when the mpy is imported. Finally, if the symbol is a function, a macro or stub should be added to ``py/dynruntime.h`` to make it easy to call the function. diff --git a/py/dynruntime.mk b/py/dynruntime.mk index cb5ab845eb1d2..43469012897cc 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -33,6 +33,11 @@ CFLAGS += -fpic -fno-common CFLAGS += -U _FORTIFY_SOURCE # prevent use of __*_chk libc functions #CFLAGS += -fdata-sections -ffunction-sections +ifneq ($(PORT),) +CFLAGS += -I$(MPY_DIR)/ports/$(PORT) +CFLAGS += -DMICROPY_PORT_FUN_TABLE +endif + MPY_CROSS_FLAGS += -march=$(ARCH) SRC_O += $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(filter %.c,$(SRC)))) @@ -137,7 +142,7 @@ $(BUILD)/%.mpy: %.py # Build native .mpy from object files $(BUILD)/$(MOD).native.mpy: $(SRC_O) $(ECHO) "LINK $<" - $(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) -o $@ $^ + $(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) $(PORT_FUN) -o $@ $^ # Build final .mpy from all intermediate .mpy files $(MOD).mpy: $(BUILD)/$(MOD).native.mpy $(SRC_MPY) diff --git a/py/mkenv.mk b/py/mkenv.mk index 371d32046227d..1608f8f0577c2 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -6,8 +6,8 @@ endif # invoked) to the top of the tree. $(lastword $(MAKEFILE_LIST)) returns # the name of this makefile relative to where make was invoked. # -# We assume that this file is in the py directory so we use $(dir ) twice -# to get to the top of the tree. +# Note that the construction of TOP fails if there is a space in the path to this makefile, +# in that case define TOP explicitly in the parent makefile or environment. THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) TOP := $(patsubst %/py/mkenv.mk,%,$(THIS_MAKEFILE)) diff --git a/py/persistentcode.c b/py/persistentcode.c index 386ea49477f6b..18331b7afdba1 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -36,6 +36,10 @@ #include "py/objstr.h" #include "py/mpthread.h" +#if MICROPY_PORT_FUN_TABLE +#include "portnativeglue.h" +#endif + #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #include "py/smallint.h" @@ -189,6 +193,13 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { #endif } +#if MICROPY_PORT_FUN_TABLE +// mp_port_fun_does_not_exist is used for mp_port_fun_table slots whose function doesn't exist +NORETURN void mp_port_fun_does_not_exist(void) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("port fun unavailable")); +} +#endif + void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) { // Relocate native code reloc_info_t *ri = ri_in; @@ -225,6 +236,17 @@ void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) { } else if (op == 6) { // Destination is mp_fun_table itself dest = (uintptr_t)&mp_fun_table; + } else if (op == 126) { + #if MICROPY_PORT_FUN_TABLE + size_t index = read_uint(ri->reader, NULL); + if (index < mp_port_fun_table_sz) { + dest = ((uintptr_t *)&mp_port_fun_table)[index]; + } else { + dest = (uintptr_t)&mp_port_fun_does_not_exist; + } + #else + mp_raise_ValueError(MP_ERROR_TEXT("no mp_port_fun_table")); + #endif } else { // Destination is an entry in mp_fun_table dest = ((uintptr_t *)&mp_fun_table)[op - 7]; diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 32bc176cb71c4..5dae88a676fd2 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -428,7 +428,7 @@ def populate_got(env): if got_entry.name == "mp_fun_table": dest = "mp_fun_table" elif got_entry.name.startswith("mp_fun_table+0x"): - dest = int(got_entry.name.split("+")[1], 16) // env.arch.word_size + dest = ("fun_table", int(got_entry.name.split("+")[1], 16)) // env.arch.word_size elif got_entry.sec_name.startswith(".text"): dest = ".text" elif got_entry.sec_name.startswith(".rodata"): @@ -437,6 +437,8 @@ def populate_got(env): dest = ".data.rel.ro" elif got_entry.sec_name.startswith(".bss"): dest = ".bss" + elif got_entry.sec_name == ".external.mp_port_fun_table": + dest = ("port_fun_table", got_entry.sym.port_fun_offset) else: assert 0, (got_entry.name, got_entry.sec_name) env.mpy_relocs.append((".text", env.got_section.addr + got_entry.offset, dest)) @@ -651,7 +653,7 @@ def do_relocation_data(env, text_addr, r): kind = sec.name elif sec.name == ".external.mp_fun_table": assert addr == 0 - kind = s.mp_fun_table_offset + kind = ("fun_table", s.mp_fun_table_offset) else: assert 0, sec.name if env.arch.separate_rodata: @@ -777,6 +779,7 @@ def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): ] ) } + port_fun_sec = Section(".external.mp_port_fun_table", b"", 0) for sym in env.unresolved_syms: assert sym["st_value"] == 0 if sym.name == "_GLOBAL_OFFSET_TABLE_": @@ -789,12 +792,20 @@ def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): sym.section = env.qstr_obj_section elif sym.name in env.known_syms: sym.resolved = env.known_syms[sym.name] + elif sym.name in fun_table: + sym.section = mp_fun_table_sec + sym.mp_fun_table_offset = fun_table[sym.name] + elif sym.name in port_fun_entries: + sym.section = port_fun_sec + sym.port_fun_offset = port_fun_entries[sym.name] + log( + LOG_LEVEL_3, + "Port_fun_table reference: {} -> port_fun_sec+{}".format( + sym.name, sym.port_fun_offset + ), + ) else: - if sym.name in fun_table: - sym.section = mp_fun_table_sec - sym.mp_fun_table_offset = fun_table[sym.name] - else: - raise LinkError("{}: undefined symbol: {}".format(sym.filename, sym.name)) + raise LinkError("{}: undefined symbol: {}".format(sym.filename, sym.name)) # Align sections, assign their addresses, and create full_text env.full_text = bytearray(env.arch.asm_jump(8)) # dummy, to be filled in later @@ -868,13 +879,35 @@ def write_qstr(self, s): self.write_bytes(s) def write_reloc(self, base, offset, dest, n): + """ + Write a relocation entry into the mpy that the dynamic linker will have to resolve + when the mpy is loaded. A relocation entry consists of a kind/op byte, followed by an + optional offset word, followed by an optional count word. + - base+offset is the location where the fixup is to be done, base is '.text' or 'rodata'. + - dest is the target whose address needs to be placed into the fixup: 0=string table, + 1=rodata_const_table, 2=bss_const_table, 3..5: unused, 6=mp_fun_table, + 7..126:entry in mp_fun_table, 1000..66535:entry in mp_port_fun_table. + - n is number of consecutive words to fix up. + """ need_offset = not (base == self.prev_base and offset == self.prev_offset + 1) self.prev_offset = offset + n - 1 - if dest <= 2: + index = None + if isinstance(dest, tuple): + if dest[0] == "port_fun_table": + # offset into mp_port_fun_table + assert dest[1] < 65536 + index = dest[1] + dest = 126 # magic number for the loader to refer to mp_port_fun_table + elif dest[0] == "fun_table": + assert 6 <= dest[1] < 126 + assert n == 1 + dest = dest[1] + else: + assert 0, dest + elif dest <= 2: dest = (dest << 1) | (n > 1) else: - assert 6 <= dest <= 127 - assert n == 1 + assert dest == 6, dest # only case left: mp_fun_table itself dest = dest << 1 | need_offset assert 0 <= dest <= 0xFE, dest self.write_bytes(bytes([dest])) @@ -884,6 +917,8 @@ def write_reloc(self, base, offset, dest, n): elif base == ".rodata": base = 1 self.write_uint(offset << 1 | base) + if index is not None: + self.write_uint(index) if n > 1: self.write_uint(n) @@ -966,8 +1001,12 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): kind = bss_const_table_idx elif kind == "mp_fun_table": kind = 6 + elif isinstance(kind, tuple) and kind[0] == "fun_table": + kind = (kind[0], 7 + kind[1]) + elif isinstance(kind, tuple) and kind[0] == "port_fun_table": + pass else: - kind = 7 + kind + assert 0, kind assert addr % env.arch.word_size == 0, addr offset = addr // env.arch.word_size if kind == prev_kind and base == prev_base and offset == prev_offset + 1: @@ -989,6 +1028,28 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): out.close() +################################################################################ +# Port-specific relocation table, which contains the addresses of a number of port-specific +# functions compiled into the firmware. These entries are used by the dynamic linker to fix-up +# relocation entries in dynamically loaded mpy modules. +port_fun_entries = {} + + +def load_port_fun(portfun_file): + """ + Load list of port-specific functions from file used for C-#include: has a function name + followed by a comma on each line + """ + ix = len(port_fun_entries) + with open(portfun_file) as f: + for l in f: + m = re.match(r"^([A-Za-z0-9_][A-Za-z0-9_]*),$", l) + if m: + port_fun_entries[m.group(1)] = ix + ix += 1 + # print("port_fun_entries=", port_fun_entries) + + ################################################################################ # main @@ -1062,6 +1123,9 @@ def main(): cmd_parser.add_argument("--arch", default="x64", help="architecture") cmd_parser.add_argument("--preprocess", action="store_true", help="preprocess source files") cmd_parser.add_argument("--qstrs", default=None, help="file defining additional qstrs") + cmd_parser.add_argument( + "--portfun", default=None, help="file defining port-specific functions" + ) cmd_parser.add_argument( "--output", "-o", default=None, help="output .mpy file (default to input with .o->.mpy)" ) @@ -1071,6 +1135,9 @@ def main(): global log_level log_level = args.verbose + if args.portfun: + load_port_fun(args.portfun) + if args.preprocess: do_preprocess(args) else: From 5bde2b982e4813c610038e4c15b484d60fe847f3 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 9 Apr 2020 17:21:38 -0700 Subject: [PATCH 2/4] esp32/mp_port_fun_table: expose esp-idf to native modules --- examples/natmod/esp32-heap/Makefile | 29 ++ examples/natmod/esp32-heap/features0.c | 46 ++ ports/esp32/Makefile | 77 ++- ports/esp32/dynruntime.mk | 16 + ports/esp32/mpconfigport.h | 1 + ports/esp32/port_fun.inc | 681 +++++++++++++++++++++++++ ports/esp32/port_fun.mk | 65 +++ ports/esp32/portnativeglue.c | 85 +++ ports/esp32/portnativeglue.h | 35 ++ 9 files changed, 1009 insertions(+), 26 deletions(-) create mode 100644 examples/natmod/esp32-heap/Makefile create mode 100644 examples/natmod/esp32-heap/features0.c create mode 100644 ports/esp32/dynruntime.mk create mode 100644 ports/esp32/port_fun.inc create mode 100644 ports/esp32/port_fun.mk create mode 100644 ports/esp32/portnativeglue.c create mode 100644 ports/esp32/portnativeglue.h diff --git a/examples/natmod/esp32-heap/Makefile b/examples/natmod/esp32-heap/Makefile new file mode 100644 index 0000000000000..b7f7a9dd59c4a --- /dev/null +++ b/examples/natmod/esp32-heap/Makefile @@ -0,0 +1,29 @@ +# Location of top-level MicroPython directory +MPY_DIR = $(abspath ../../..) + +# Name of module +MOD = esp32heap + +# Source files (.c or .py) +SRC = features0.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = xtensawin + +PORT = esp32 + +# Location of MicroPython source tree +TOP := $(abspath ../../..) + +# Espressif ESP-IDF path +IDF_PATH ?= $(abspath $(TOP)/../esp-idf-micropython) + +# xtensa toolchain bin dir +PATH := $(abspath $(TOP)/../xtensa-esp32-elf-8.2.0/bin):$(PATH) + +# Board to get correct ESP-IDF config +BOARD ?= GENERIC + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk +include $(MPY_DIR)/ports/$(PORT)/dynruntime.mk diff --git a/examples/natmod/esp32-heap/features0.c b/examples/natmod/esp32-heap/features0.c new file mode 100644 index 0000000000000..ad7ea1acce72e --- /dev/null +++ b/examples/natmod/esp32-heap/features0.c @@ -0,0 +1,46 @@ +/* This example demonstrates the following features in a native module: + - defining a simple function exposed to Python + - defining a local, helper C function + - getting and creating integer objects +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" +// Include esp-idf include files +#include "esp_system.h" + +// This is the function which will be called from Python, as free_heap() +STATIC mp_obj_t free_heap() { + // calling an ESP-IDF function + uint32_t f = esp_get_free_heap_size(); + // sample debug printf + mp_printf(&mp_plat_print, "esp_get_free_heap_size returned %d\n", f); + // return integer as MP small int object + return mp_obj_new_int(f); +} +// Define a Python reference to the function above +STATIC MP_DEFINE_CONST_FUN_OBJ_0(free_heap_obj, free_heap); + +// This a function that only exists in esp-idf-v4, it will raise in esp-idf-v3. +STATIC mp_obj_t flash_encryption_mode() { + // calling an ESP-IDF function that doesn't exist in v3 + extern uint32_t esp_get_flash_encryption_mode(); + uint32_t f = esp_get_flash_encryption_mode(); + // return integer as MP small int object + return mp_obj_new_int(f); +} +// Define a Python reference to the function above +STATIC MP_DEFINE_CONST_FUN_OBJ_0(flash_encryption_mode_obj, flash_encryption_mode); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the functions available in the module's namespace + mp_store_global(MP_QSTR_free_heap, MP_OBJ_FROM_PTR(&free_heap_obj)); + mp_store_global(MP_QSTR_flash_encryption_mode, MP_OBJ_FROM_PTR(&flash_encryption_mode_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 0789455854ef1..877d5e61c32a2 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -1,3 +1,14 @@ +# get the directory where this makefile resides +# fails if the path has a space :-(, if that happens define PORT_DIR in the parent makefile +PORT_DIR ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +PORT_DIR := $(PORT_DIR) +$(info PORT_DIR=$(PORT_DIR)) + +# if the parent makefile defines MPY_DIR then use that also for TOP (normally generated in mkenv.mk) +ifneq ($(MPY_DIR),) +TOP ?= $(MPY_DIR) +endif + # Select the board to build for: if not given on the command line, # then default to GENERIC. BOARD ?= GENERIC @@ -5,15 +16,15 @@ BOARD ?= GENERIC # If the build directory is not given, make it reflect the board name. BUILD ?= build-$(BOARD) -BOARD_DIR ?= boards/$(BOARD) +BOARD_DIR ?= $(PORT_DIR)/boards/$(BOARD) ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) endif -include ../../py/mkenv.mk +include $(PORT_DIR)/../../py/mkenv.mk # Optional (not currently used for ESP32) --include mpconfigport.mk +-include $(PORT_DIR)/mpconfigport.mk ifneq ($(SDKCONFIG),) $(error Use the BOARD variable instead of SDKCONFIG) @@ -129,6 +140,7 @@ include $(TOP)/extmod/nimble/nimble.mk endif # include sdkconfig to get needed configuration values +SDKCONFIG := $(addprefix $(PORT_DIR)/, $(SDKCONFIG)) include $(SDKCONFIG) ################################################################################ @@ -253,6 +265,32 @@ CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 endif +################################################################################ +# Generate sdkconfig.h from sdkconfig + +$(SDKCONFIG_COMBINED): $(SDKCONFIG) + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(CAT) $^ > $@ + +$(SDKCONFIG_H): $(SDKCONFIG_COMBINED) + $(ECHO) "GEN $@" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \ + --output header $@ \ + --config $< \ + --kconfig $(ESPIDF)/Kconfig \ + --env "IDF_TARGET=esp32" \ + --env "IDF_CMAKE=n" \ + --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ + --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ + --env "IDF_PATH=$(ESPIDF)" + $(Q)touch $@ + +$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard.h + +# The rest of this Makefile is not needed to build dynamic native modules +ifndef MPY_DYNRUNTIME + # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ -mlongcalls -nostdlib \ @@ -354,6 +392,7 @@ SRC_C = \ mpthreadport.c \ machine_rtc.c \ machine_sdcard.c \ + portnativeglue.c \ $(wildcard $(BOARD_DIR)/*.c) \ $(SRC_MOD) @@ -387,29 +426,6 @@ SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) # Append any auto-generated sources that are needed by sources listed in SRC_QSTR SRC_QSTR_AUTO_DEPS += -################################################################################ -# Generate sdkconfig.h from sdkconfig - -$(SDKCONFIG_COMBINED): $(SDKCONFIG) - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(CAT) $^ > $@ - -$(SDKCONFIG_H): $(SDKCONFIG_COMBINED) - $(ECHO) "GEN $@" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \ - --output header $@ \ - --config $< \ - --kconfig $(ESPIDF)/Kconfig \ - --env "IDF_TARGET=esp32" \ - --env "IDF_CMAKE=n" \ - --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ - --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ - --env "IDF_PATH=$(ESPIDF)" - $(Q)touch $@ - -$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard.h - ################################################################################ # List of object files from the ESP32 IDF components @@ -777,6 +793,7 @@ $(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.pro $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) $(Q)$(SIZE) $@ + $(Q)$(SIZE) -A $@ | egrep iram0.text | sed -e 's/ */: /' -e 's; *[^ ]*$$; of 131072;' define compile_cxx $(ECHO) "CXX $<" @@ -794,6 +811,12 @@ vpath %.cpp . $(TOP) $(BUILD)/%.o: %.cpp $(call compile_cxx) +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) +$(BUILD)/portnativeglue.o: CFLAGS := $(filter-out -Werror, $(CFLAGS)) +else +$(BUILD)/portnativeglue.o: CFLAGS += -Wno-builtin-declaration-mismatch +endif + ################################################################################ # Declarations to build the bootloader @@ -979,3 +1002,5 @@ $(BUILD)/partitions.bin: $(PART_SRC) ################################################################################ include $(TOP)/py/mkrules.mk + +endif # MPY_DYNRUNTIME diff --git a/ports/esp32/dynruntime.mk b/ports/esp32/dynruntime.mk new file mode 100644 index 0000000000000..f08d27d51bded --- /dev/null +++ b/ports/esp32/dynruntime.mk @@ -0,0 +1,16 @@ +# Makefile to include after py/dynruntime.mk in order to add esp32-specific rules +# for building native modules that include esp-idf header files and call esp-idf functions. + +PORT_DIR := $(MPY_DIR)/ports/esp32 + +MPY_DYNRUNTIME := 1 +include $(PORT_DIR)/Makefile + +CFLAGS += -std=gnu99 # override -std=c99 in dynruntime.mk +CFLAGS += $(INC) $(INC_ESPCOMP) $(CFLAGS_MOD) + +# Make all module object files depend on sdkconfig +$(SRC_O): $(SDKCONFIG_H) + +# Tell mpy_ld to load port-specific function table +PORT_FUN=--portfun $(PORT_DIR)/port_fun.inc diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 72ecfadc6b29b..760a35add29ef 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -59,6 +59,7 @@ #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_VFS (1) +#define MICROPY_PORT_FUN_TABLE (1) // control over Python builtins #define MICROPY_PY_FUNCTION_ATTRS (1) diff --git a/ports/esp32/port_fun.inc b/ports/esp32/port_fun.inc new file mode 100644 index 0000000000000..8cedc057d777a --- /dev/null +++ b/ports/esp32/port_fun.inc @@ -0,0 +1,681 @@ +// The contents of this file is semi-automatically generated. It has two sections, the first has +// libc functions and the second has ESP-IDF functions, all of which are made available to +// dynamically loaded native modules. +// The order of functions matters! Changing the order breaks comaptibility! +// To add functions to the end, run make -f port_fun.mk, then see what's new (in port_fun_new.inc) +// and manually copy the desired functions over. +// +// +// First section: +// List of libc entry points that are already linked into MP for inclusion into mp_port_fun_table +// Obtained using something like: +// xtensa-esp32-elf-nm --extern-only build-GENERIC/application.elf | grep ' A ' | +// sed -e 's/^.* [TA] //' | sort -u >externs-mp +// +// sort externs-libc1 externs-mp1 | uniq -c | egrep ' 2 ' | egrep -v ' _' | sed -e 's/.* //' >libc.inc +abs, +asctime, +asctime_r, +atoi, +atol, +bzero, +creat, +ctime, +ctime_r, +div, +fclose, +fflush, +fputwc, +gmtime, +gmtime_r, +isalnum, +isalpha, +isascii, +isblank, +iscntrl, +isdigit, +isgraph, +islower, +isprint, +ispunct, +isspace, +isupper, +itoa, +labs, +ldiv, +localeconv, +localtime, +localtime_r, +longjmp, +memccpy, +memchr, +memcmp, +memcpy, +memmove, +memrchr, +memset, +mktime, +qsort, +rand, +rand_r, +setjmp, +setlocale, +srand, +strcasecmp, +strcasestr, +strcat, +strchr, +strcmp, +strcoll, +strcpy, +strcspn, +strdup, +strftime, +strlcat, +strlcpy, +strlen, +strlwr, +strncasecmp, +strncat, +strncmp, +strncpy, +strndup, +strnlen, +strrchr, +strsep, +strspn, +strstr, +strtok_r, +strtol, +strtoul, +strupr, +time, +toascii, +tolower, +toupper, +tzset, +ungetc, +utoa, +wcrtomb, +// +// Second section: +// List of ESP-IDF entry points culled from portions of the docs. +// Initially generated for ESP-IDF v4.0 release using 'port_fun' target in Makefile. +// Use that Makefile target to add new functions to the end of the list. +adc1_config_channel_atten, +adc1_config_width, +adc1_get_raw, +adc1_pad_get_io_num, +adc1_ulp_enable, +adc2_config_channel_atten, +adc2_get_raw, +adc2_pad_get_io_num, +adc2_vref_to_gpio, +adc_gpio_init, +adc_i2s_mode_init, +adc_power_off, +adc_power_on, +adc_set_clk_div, +adc_set_data_inv, +adc_set_data_width, +adc_set_i2s_data_source, +can_clear_receive_queue, +can_clear_transmit_queue, +can_driver_install, +can_driver_uninstall, +can_get_status_info, +can_initiate_recovery, +can_read_alerts, +can_receive, +can_reconfigure_alerts, +can_start, +can_stop, +can_transmit, +dac_i2s_disable, +dac_i2s_enable, +dac_output_disable, +dac_output_enable, +dac_output_voltage, +dac_pad_get_io_num, +esp_base_mac_addr_get, +esp_base_mac_addr_set, +esp_chip_info, +esp_deep_sleep, +esp_deep_sleep_disable_rom_logging, +esp_deep_sleep_start, +esp_default_wake_deep_sleep, +esp_deregister_freertos_idle_hook, +esp_deregister_freertos_idle_hook_for_cpu, +esp_deregister_freertos_tick_hook, +esp_deregister_freertos_tick_hook_for_cpu, +esp_derive_local_mac, +esp_efuse_apply_34_encoding, +esp_efuse_burn_new_values, +esp_efuse_check_secure_version, +esp_efuse_disable_basic_rom_console, +esp_efuse_get_chip_ver, +esp_efuse_get_coding_scheme, +esp_efuse_get_field_size, +esp_efuse_get_pkg_ver, +esp_efuse_mac_get_custom, +esp_efuse_mac_get_default, +esp_efuse_read_block, +esp_efuse_read_field_blob, +esp_efuse_read_field_cnt, +esp_efuse_read_reg, +esp_efuse_read_secure_version, +esp_efuse_reset, +esp_efuse_set_read_protect, +esp_efuse_set_write_protect, +esp_efuse_update_secure_version, +esp_efuse_write_block, +esp_efuse_write_field_blob, +esp_efuse_write_field_cnt, +esp_efuse_write_random_key, +esp_efuse_write_reg, +esp_err_to_name, +esp_err_to_name_r, +esp_fill_random, +esp_flash_encryption_init_checks, +esp_flash_write_protect_crypt_cnt, +esp_get_deep_sleep_wake_stub, +esp_get_flash_encryption_mode, +esp_get_free_heap_size, +esp_get_idf_version, +esp_get_minimum_free_heap_size, +esp_intr_alloc, +esp_intr_alloc_intrstatus, +esp_intr_disable, +esp_intr_enable, +esp_intr_free, +esp_intr_get_cpu, +esp_intr_get_intno, +esp_intr_mark_shared, +esp_intr_noniram_disable, +esp_intr_noniram_enable, +esp_intr_reserve, +esp_intr_set_in_iram, +esp_int_wdt_cpu_init, +esp_int_wdt_init, +esp_ipc_call, +esp_ipc_call_blocking, +esp_light_sleep_start, +esp_ota_begin, +esp_ota_check_rollback_is_possible, +esp_ota_end, +esp_ota_erase_last_boot_app_partition, +esp_ota_get_app_description, +esp_ota_get_app_elf_sha256, +esp_ota_get_boot_partition, +esp_ota_get_last_invalid_partition, +esp_ota_get_next_update_partition, +esp_ota_get_partition_description, +esp_ota_get_running_partition, +esp_ota_get_state_partition, +esp_ota_mark_app_invalid_rollback_and_reboot, +esp_ota_mark_app_valid_cancel_rollback, +esp_ota_set_boot_partition, +esp_ota_write, +esp_pm_configure, +esp_pm_dump_locks, +esp_pm_lock_acquire, +esp_pm_lock_create, +esp_pm_lock_delete, +esp_pm_lock_release, +esp_random, +esp_read_mac, +esp_register_freertos_idle_hook, +esp_register_freertos_idle_hook_for_cpu, +esp_register_freertos_tick_hook, +esp_register_freertos_tick_hook_for_cpu, +esp_register_shutdown_handler, +esp_reset_reason, +esp_restart, +esp_set_deep_sleep_wake_stub, +esp_sleep_disable_wakeup_source, +esp_sleep_enable_ext0_wakeup, +esp_sleep_enable_ext1_wakeup, +esp_sleep_enable_gpio_wakeup, +esp_sleep_enable_timer_wakeup, +esp_sleep_enable_touchpad_wakeup, +esp_sleep_enable_uart_wakeup, +esp_sleep_enable_ulp_wakeup, +esp_sleep_get_ext1_wakeup_status, +esp_sleep_get_touchpad_wakeup_status, +esp_sleep_get_wakeup_cause, +esp_sleep_pd_config, +esp_task_wdt_add, +esp_task_wdt_deinit, +esp_task_wdt_delete, +esp_task_wdt_init, +esp_task_wdt_reset, +esp_task_wdt_status, +esp_timer_create, +esp_timer_deinit, +esp_timer_delete, +esp_timer_dump, +esp_timer_get_next_alarm, +esp_timer_get_time, +esp_timer_init, +esp_timer_start_once, +esp_timer_start_periodic, +esp_timer_stop, +esp_unregister_shutdown_handler, +esp_wifi_deinit, +esp_wifi_init, +gpio_config, +gpio_deep_sleep_hold_dis, +gpio_deep_sleep_hold_en, +gpio_get_drive_capability, +gpio_get_level, +gpio_hold_dis, +gpio_hold_en, +gpio_install_isr_service, +gpio_intr_disable, +gpio_intr_enable, +gpio_iomux_in, +gpio_iomux_out, +gpio_isr_handler_add, +gpio_isr_handler_remove, +gpio_isr_register, +gpio_pulldown_dis, +gpio_pulldown_en, +gpio_pullup_dis, +gpio_pullup_en, +gpio_reset_pin, +gpio_set_direction, +gpio_set_drive_capability, +gpio_set_intr_type, +gpio_set_level, +gpio_set_pull_mode, +gpio_uninstall_isr_service, +gpio_wakeup_disable, +gpio_wakeup_enable, +hall_sensor_read, +i2c_cmd_link_create, +i2c_cmd_link_delete, +i2c_driver_delete, +i2c_driver_install, +i2c_filter_disable, +i2c_filter_enable, +i2c_get_data_mode, +i2c_get_data_timing, +i2c_get_period, +i2c_get_start_timing, +i2c_get_stop_timing, +i2c_get_timeout, +i2c_isr_free, +i2c_isr_register, +i2c_master_cmd_begin, +i2c_master_read, +i2c_master_read_byte, +i2c_master_start, +i2c_master_stop, +i2c_master_write, +i2c_master_write_byte, +i2c_param_config, +i2c_reset_rx_fifo, +i2c_reset_tx_fifo, +i2c_set_data_mode, +i2c_set_data_timing, +i2c_set_period, +i2c_set_pin, +i2c_set_start_timing, +i2c_set_stop_timing, +i2c_set_timeout, +i2c_slave_read_buffer, +i2c_slave_write_buffer, +i2s_adc_disable, +i2s_adc_enable, +i2s_driver_install, +i2s_driver_uninstall, +i2s_get_clk, +i2s_read, +i2s_set_adc_mode, +i2s_set_clk, +i2s_set_dac_mode, +i2s_set_pdm_rx_down_sample, +i2s_set_pin, +i2s_set_sample_rates, +i2s_start, +i2s_stop, +i2s_write, +i2s_write_expand, +i2s_zero_dma_buffer, +ledc_bind_channel_timer, +ledc_channel_config, +ledc_fade_func_install, +ledc_fade_func_uninstall, +ledc_fade_start, +ledc_get_duty, +ledc_get_freq, +ledc_get_hpoint, +ledc_isr_register, +ledc_set_duty, +ledc_set_duty_and_update, +ledc_set_duty_with_hpoint, +ledc_set_fade, +ledc_set_fade_step_and_start, +ledc_set_fade_time_and_start, +ledc_set_fade_with_step, +ledc_set_fade_with_time, +ledc_set_freq, +ledc_stop, +ledc_timer_config, +ledc_timer_pause, +ledc_timer_resume, +ledc_timer_rst, +ledc_timer_set, +ledc_update_duty, +mcpwm_capture_disable, +mcpwm_capture_enable, +mcpwm_capture_signal_get_edge, +mcpwm_capture_signal_get_value, +mcpwm_carrier_disable, +mcpwm_carrier_enable, +mcpwm_carrier_init, +mcpwm_carrier_oneshot_mode_disable, +mcpwm_carrier_oneshot_mode_enable, +mcpwm_carrier_output_invert, +mcpwm_carrier_set_duty_cycle, +mcpwm_carrier_set_period, +mcpwm_deadtime_disable, +mcpwm_deadtime_enable, +mcpwm_fault_deinit, +mcpwm_fault_init, +mcpwm_fault_set_cyc_mode, +mcpwm_fault_set_oneshot_mode, +mcpwm_get_duty, +mcpwm_get_frequency, +mcpwm_gpio_init, +mcpwm_init, +mcpwm_isr_register, +mcpwm_set_duty, +mcpwm_set_duty_in_us, +mcpwm_set_duty_type, +mcpwm_set_frequency, +mcpwm_set_pin, +mcpwm_set_signal_high, +mcpwm_set_signal_low, +mcpwm_start, +mcpwm_stop, +mcpwm_sync_disable, +mcpwm_sync_enable, +mdns_free, +mdns_handle_system_event, +mdns_hostname_set, +mdns_init, +mdns_instance_name_set, +mdns_query, +mdns_query_a, +mdns_query_aaaa, +mdns_query_ptr, +mdns_query_results_free, +mdns_query_srv, +mdns_query_txt, +mdns_service_add, +mdns_service_instance_name_set, +mdns_service_port_set, +mdns_service_remove, +mdns_service_remove_all, +mdns_service_txt_item_remove, +mdns_service_txt_item_set, +mdns_service_txt_set, +nvs_close, +nvs_commit, +nvs_entry_find, +nvs_entry_info, +nvs_entry_next, +nvs_erase_all, +nvs_erase_key, +nvs_flash_deinit, +nvs_flash_deinit_partition, +nvs_flash_erase, +nvs_flash_erase_partition, +nvs_flash_init, +nvs_flash_init_partition, +nvs_get_blob, +nvs_get_i16, +nvs_get_i32, +nvs_get_i64, +nvs_get_i8, +nvs_get_stats, +nvs_get_str, +nvs_get_u16, +nvs_get_u32, +nvs_get_u64, +nvs_get_u8, +nvs_get_used_entry_count, +nvs_open, +nvs_open_from_partition, +nvs_release_iterator, +nvs_set_blob, +nvs_set_i16, +nvs_set_i32, +nvs_set_i64, +nvs_set_i8, +nvs_set_str, +nvs_set_u16, +nvs_set_u32, +nvs_set_u64, +nvs_set_u8, +pcnt_counter_clear, +pcnt_counter_pause, +pcnt_counter_resume, +pcnt_event_disable, +pcnt_event_enable, +pcnt_filter_disable, +pcnt_filter_enable, +pcnt_get_counter_value, +pcnt_get_event_value, +pcnt_get_filter_value, +pcnt_intr_disable, +pcnt_intr_enable, +pcnt_isr_handler_add, +pcnt_isr_handler_remove, +pcnt_isr_register, +pcnt_isr_service_install, +pcnt_isr_service_uninstall, +pcnt_set_event_value, +pcnt_set_filter_value, +pcnt_set_mode, +pcnt_set_pin, +pcnt_unit_config, +pcTimerGetTimerName, +pvTimerGetTimerID, +rmt_clr_intr_enable_mask, +rmt_config, +rmt_driver_install, +rmt_driver_uninstall, +rmt_fill_tx_items, +rmt_get_channel_status, +rmt_get_clk_div, +rmt_get_idle_level, +rmt_get_mem_block_num, +rmt_get_memory_owner, +rmt_get_mem_pd, +rmt_get_ringbuf_handle, +rmt_get_rx_idle_thresh, +rmt_get_source_clk, +rmt_get_status, +rmt_get_tx_loop_mode, +rmt_isr_deregister, +rmt_isr_register, +rmt_memory_rw_rst, +rmt_register_tx_end_callback, +rmt_rx_start, +rmt_rx_stop, +rmt_set_clk_div, +rmt_set_err_intr_en, +rmt_set_idle_level, +rmt_set_intr_enable_mask, +rmt_set_mem_block_num, +rmt_set_memory_owner, +rmt_set_mem_pd, +rmt_set_pin, +rmt_set_rx_filter, +rmt_set_rx_idle_thresh, +rmt_set_rx_intr_en, +rmt_set_source_clk, +rmt_set_tx_carrier, +rmt_set_tx_intr_en, +rmt_set_tx_loop_mode, +rmt_set_tx_thr_intr_en, +rmt_translator_init, +rmt_tx_start, +rmt_tx_stop, +rmt_wait_tx_done, +rmt_write_items, +rmt_write_sample, +rtc_gpio_deinit, +rtc_gpio_force_hold_dis_all, +rtc_gpio_get_drive_capability, +rtc_gpio_get_level, +rtc_gpio_hold_dis, +rtc_gpio_hold_en, +rtc_gpio_init, +rtc_gpio_isolate, +rtc_gpio_pulldown_dis, +rtc_gpio_pulldown_en, +rtc_gpio_pullup_dis, +rtc_gpio_pullup_en, +rtc_gpio_set_direction, +rtc_gpio_set_drive_capability, +rtc_gpio_set_level, +rtc_gpio_wakeup_disable, +rtc_gpio_wakeup_enable, +sdio_slave_clear_host_int, +sdio_slave_deinit, +sdio_slave_get_host_intena, +sdio_slave_initialize, +sdio_slave_read_reg, +sdio_slave_recv, +sdio_slave_recv_get_buf, +sdio_slave_recv_load_buf, +sdio_slave_recv_register_buf, +sdio_slave_recv_unregister_buf, +sdio_slave_reset, +sdio_slave_send_get_finished, +sdio_slave_send_host_int, +sdio_slave_send_queue, +sdio_slave_set_host_intena, +sdio_slave_start, +sdio_slave_stop, +sdio_slave_transmit, +sdio_slave_wait_int, +sdio_slave_write_reg, +sdmmc_card_init, +sdmmc_card_print_info, +sdmmc_host_deinit, +sdmmc_host_do_transaction, +sdmmc_host_get_slot_width, +sdmmc_host_init, +sdmmc_host_init_slot, +sdmmc_host_io_int_enable, +sdmmc_host_io_int_wait, +sdmmc_host_pullup_en, +sdmmc_host_set_bus_ddr_mode, +sdmmc_host_set_bus_width, +sdmmc_host_set_card_clk, +sdmmc_io_enable_int, +sdmmc_io_get_cis_data, +sdmmc_io_print_cis_info, +sdmmc_io_read_blocks, +sdmmc_io_read_byte, +sdmmc_io_read_bytes, +sdmmc_io_wait_int, +sdmmc_io_write_blocks, +sdmmc_io_write_byte, +sdmmc_io_write_bytes, +sdmmc_read_sectors, +sdmmc_write_sectors, +sdspi_host_deinit, +sdspi_host_do_transaction, +sdspi_host_init, +sdspi_host_init_slot, +sdspi_host_io_int_enable, +sdspi_host_io_int_wait, +sdspi_host_set_card_clk, +sigmadelta_config, +sigmadelta_set_duty, +sigmadelta_set_pin, +sigmadelta_set_prescale, +spi_bus_free, +spi_bus_initialize, +timer_disable_intr, +timer_enable_intr, +timer_get_alarm_value, +timer_get_config, +timer_get_counter_time_sec, +timer_get_counter_value, +timer_group_intr_disable, +timer_group_intr_enable, +timer_init, +timer_isr_register, +timer_pause, +timer_set_alarm, +timer_set_alarm_value, +timer_set_auto_reload, +timer_set_counter_mode, +timer_set_counter_value, +timer_set_divider, +timer_start, +uart_clear_intr_status, +uart_disable_intr_mask, +uart_disable_pattern_det_intr, +uart_disable_rx_intr, +uart_disable_tx_intr, +uart_driver_delete, +uart_driver_install, +uart_enable_intr_mask, +uart_enable_pattern_det_intr, +uart_enable_rx_intr, +uart_enable_tx_intr, +uart_flush, +uart_flush_input, +uart_get_baudrate, +uart_get_buffered_data_len, +uart_get_collision_flag, +uart_get_hw_flow_ctrl, +uart_get_parity, +uart_get_stop_bits, +uart_get_wakeup_threshold, +uart_get_word_length, +uart_intr_config, +uart_isr_free, +uart_isr_register, +uart_param_config, +uart_pattern_get_pos, +uart_pattern_pop_pos, +uart_pattern_queue_reset, +uart_read_bytes, +uart_set_baudrate, +uart_set_dtr, +uart_set_hw_flow_ctrl, +uart_set_line_inverse, +uart_set_mode, +uart_set_parity, +uart_set_pin, +uart_set_rts, +uart_set_rx_timeout, +uart_set_stop_bits, +uart_set_sw_flow_ctrl, +uart_set_tx_idle_num, +uart_set_wakeup_threshold, +uart_set_word_length, +uart_tx_chars, +uart_wait_tx_done, +uart_write_bytes, +uart_write_bytes_with_break, +ulp_load_binary, +ulp_process_macros_and_load, +ulp_run, +ulp_set_wakeup_period, +vTimerSetTimerID, +xTimerCreate, +xTimerCreateStatic, +xTimerGetExpiryTime, +xTimerGetPeriod, +xTimerIsTimerActive, +xTimerPendFunctionCall, +xTimerPendFunctionCallFromISR, diff --git a/ports/esp32/port_fun.mk b/ports/esp32/port_fun.mk new file mode 100644 index 0000000000000..f14e9a9b8c550 --- /dev/null +++ b/ports/esp32/port_fun.mk @@ -0,0 +1,65 @@ +# Makefile to create the port-specific functions table for dynamic linking +# +# The port functions table is created by culling function names from the ESP-IDF doxygen +# docs and then massaging that list. Some sections are excluded because referring to all these +# functins pulls them into the build and then iram overflows. +# In addition to the EDP-IDF function a good number of libc functions were pulled in manually. +# +# Running the 'all' target in this makefile generates a fresh list and then compares whether +# anything new shows up compared to the existing function list. These must then be added manually as +# desired. + +# Start by pulling in common makefile (used to build firmware and native modules) +include esp32-common.mk + +all: $(BUILD)/port_fun_new.inc + $(Q)if [ ! -s $< ]; then echo "No new functions"; else echo `wc -l <$<`' new functions, see' $<; fi + + +# List of doxygen-generated include files from the esp-idf documentation from which to cull public +# function names. These files are found in $(ESPIDF)/docs/en/_build/inc/*.inc +# The inclusion of some function sets causes the .iram.text segment to grow and easily +# overflow, this is why only selected files are listed. The "adds" comments indicate how many bytes +# each line adds to iram.text (which has a bit over 4KB free as of MP v1.12 w/IDF v4.0). +PORT_FUN_INC := adc adc_channel can dac dac_channel esp_adc_cal gpio i2c i2s # adds 0 +PORT_FUN_INC += esp_efuse esp_err esp_err_defs esp_freertos_hooks esp_flash_encrypt # adds 0 +PORT_FUN_INC += esp_idf_version esp_intr_alloc esp_int_wdt esp_ipc esp_mesh # adds 116 +PORT_FUN_INC += esp_modbus_common esp_modbus_master esp_modbus_slave # adds 0 +PORT_FUN_INC += esp_now esp_ota_ops esp_pm esp_sleep esp_system # adds 12 +PORT_FUN_INC += esp_task_wdt esp_timer esp_tls # adds 36 +PORT_FUN_INC += esp_wifi esp_wifi_types wifi_config wifi_scan # adds 0 +PORT_FUN_INC += ledc mcpwm mdns nvs nvs_flash pcnt pm rmt scratch-build-code sigmadelta # adds 360 +PORT_FUN_INC += rtc_gpio_channel rtc_io ulp # adds 0 +PORT_FUN_INC += sdio_slave sdmmc_cmd sdmmc_host sdmmc_types sdspi_host spi_common # adds 0 +PORT_FUN_INC += timer timers uart # adds 284 (uart) +#PORT_FUN_INC += esp_flash # adds 2192 to iram +#PORT_FUN_INC += multi_heap # adds 484 to iram +#PORT_FUN_INC += spi_master # adds 796 to iram +#PORT_FUN_INC += spi_slave # adds 1148 to iram +#PORT_FUN_INC += task # adds 2124 to iram +#PORT_FUN_INC += touch_channel # adds 444 to iram +PORT_FUN_INC := $(addprefix $(ESPIDF)/docs/en/_build/inc/, $(addsuffix *.inc, $(PORT_FUN_INC))) + +# new functions found but not listed in port_fun.inc, typ these are new features added to esp-idf +# and perhaps should be manually added to the end of port_fun.inc +$(BUILD)/port_fun_new.inc: $(BUILD)/port_fun_all.inc port_fun.inc + $(ECHO) "Generating $@" + $(Q)diff port_fun.inc $< | grep '^>' | sed -e 's/^> *//' >$@ + +# all functions mentioned in the esp-idf API reference docs +$(BUILD)/port_fun_docfuns: $(PORT_FUN_INC) + $(ECHO) "Generating $@" + $(Q)grep doxygenfunction:: $^ | \ + egrep -v _Static_assert | \ + sed -e 's/.*:: *//' -e '/^$$/d' | sort -u >$@ + +# all exported symbols from esp-idf libraries +$(BUILD)/port_fun_exports: $(BUILD_ESPIDF_LIB)/*/*.a + $(ECHO) "Generating $@" + $(Q)xtensa-esp32-elf-nm --extern-only $^ | grep ' T ' | sed -e 's/^.* //' | sort -u > $@ + +# all functions in the esp-idf docs that are also exported, ready to be #included +$(BUILD)/port_fun_all.inc: $(BUILD)/port_fun_exports $(BUILD)/port_fun_docfuns + $(ECHO) "Generating $@" + $(Q)sort $^ | uniq -c | grep '^ *2 ' | sed -e 's/^ *2 //' -e 's/$$/,/' > $@ + diff --git a/ports/esp32/portnativeglue.c b/ports/esp32/portnativeglue.c new file mode 100644 index 0000000000000..cad7be452100e --- /dev/null +++ b/ports/esp32/portnativeglue.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared & Thorsten von Eicken + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// We need the MICROPY_PORT_FUN_TABLE #define from mpconfigport.h but need to exclude pulling in the +// rest of the .h world because it spoils the phony "voidfun" type decl below. We #define some +// XXX_H defines to prevent recursive inclusion. +#define _STDINT_H +#define _NEWLIB_ALLOCA_H +#define _SYS_TYPES_H +#define _ROM_ETS_SYS_H_ +#define INC_FREERTOS_H +typedef int size_t; +typedef int int32_t; +typedef unsigned int uint32_t; +#include "mpconfigport.h" + +#if MICROPY_PORT_FUN_TABLE + +#if !MICROPY_ESP_IDF_4 +// A bunch of functions don't exist in ESP-IDF v3.3, so we need dummies +#define esp_flash_encryption_init_checks mp_port_fun_does_not_exist +#define esp_get_flash_encryption_mode mp_port_fun_does_not_exist +#define esp_unregister_shutdown_handler mp_port_fun_does_not_exist +#define nvs_entry_find mp_port_fun_does_not_exist +#define nvs_entry_info mp_port_fun_does_not_exist +#define nvs_entry_next mp_port_fun_does_not_exist +#define nvs_release_iterator mp_port_fun_does_not_exist +#define sdmmc_io_get_cis_data mp_port_fun_does_not_exist +#define sdmmc_io_print_cis_info mp_port_fun_does_not_exist +#define sdspi_host_io_int_enable mp_port_fun_does_not_exist +#define sdspi_host_io_int_wait mp_port_fun_does_not_exist +#endif + +#include "portnativeglue.h" + +// mp_port_fun_table below is a table of C functions to which a dynamically loaded native module can +// link. Typically it is populated with ESP-IDF functions, but it can really contain any 'extern' C +// function. +// The bulk of the table comes from port_fun.inc, which is a file of comma-separated function +// names, one function per line. The content of this file must be managed manually because the order +// of existing functions must remain the same so old mpy files can continue to be linked correctly, +// i.e. new functions should always be added to the end. +// The port_fun.mk makefile aids in managing the list of potential new functions. +// The functions come from the intersection of the esp-idf api reference documentation and the +// symbols found in the firmware. This process requires that the esp-idf docs be built first (cd +// $ESPIDF/docs/en; make xml). + +// declare all the functions we reference as "void foo(void)" so we can build an array +typedef void voidfun(void); +extern voidfun +#include "port_fun.inc" +__notused__; + +// Create static array of function pointers. +// This table plus the code it references (that might otherwise be excluded by the linker) consumes +// an extra 65KB of text (~6%) and 16KB of data (~6%). +const mp_port_fun_table_t mp_port_fun_table = { + #include "port_fun.inc" +}; +const size_t mp_port_fun_table_sz = sizeof(mp_port_fun_table) / sizeof(mp_port_fun_ptr_t); + +#endif // MICROPY_PORT_FUN_TABLE diff --git a/ports/esp32/portnativeglue.h b/ports/esp32/portnativeglue.h new file mode 100644 index 0000000000000..1a7d6940e9745 --- /dev/null +++ b/ports/esp32/portnativeglue.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared & Thorsten von Eicken + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_PORTNATIVEGLUE_H +#define MICROPY_INCLUDED_ESP32_PORTNATIVEGLUE_H + +typedef void (*mp_port_fun_ptr_t)(void); // pointer to arg-less function returning void +typedef mp_port_fun_ptr_t mp_port_fun_table_t[]; +extern const mp_port_fun_table_t mp_port_fun_table; +extern const size_t mp_port_fun_table_sz; + +#endif // MICROPY_INCLUDED_ESP32_PORTNATIVEGLUE_H From 8edb4546a48d56f9dff7148a4c4e32286b4bc464 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 7 May 2020 00:45:00 -0700 Subject: [PATCH 3/4] esp32: fix port_fun.mk so it works with re-unified Makefile --- ports/esp32/port_fun.mk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/esp32/port_fun.mk b/ports/esp32/port_fun.mk index f14e9a9b8c550..2df7d43a47fd2 100644 --- a/ports/esp32/port_fun.mk +++ b/ports/esp32/port_fun.mk @@ -5,14 +5,15 @@ # functins pulls them into the build and then iram overflows. # In addition to the EDP-IDF function a good number of libc functions were pulled in manually. # -# Running the 'all' target in this makefile generates a fresh list and then compares whether +# Running the 'port_fun_new' target in this makefile generates a fresh list and then compares whether # anything new shows up compared to the existing function list. These must then be added manually as # desired. # Start by pulling in common makefile (used to build firmware and native modules) -include esp32-common.mk +#MPY_DYNRUNTIME := 1 +include Makefile -all: $(BUILD)/port_fun_new.inc +port_fun_new: $(BUILD)/port_fun_new.inc $(Q)if [ ! -s $< ]; then echo "No new functions"; else echo `wc -l <$<`' new functions, see' $<; fi From be988604eafe4bb4bd70957e5a836f7d8aba25ed Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 8 May 2020 13:14:10 -0700 Subject: [PATCH 4/4] esp32/port_fun: add settimeofday --- lib/mynewt-nimble | 2 +- ports/esp32/port_fun.inc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mynewt-nimble b/lib/mynewt-nimble index 223714cb16c25..97ce3eacaaa79 160000 --- a/lib/mynewt-nimble +++ b/lib/mynewt-nimble @@ -1 +1 @@ -Subproject commit 223714cb16c255cfa701929c0de6d7579bfd2cdd +Subproject commit 97ce3eacaaa79e8ed6cf71717149ced4f5328ee7 diff --git a/ports/esp32/port_fun.inc b/ports/esp32/port_fun.inc index 8cedc057d777a..dc3e2b0541b40 100644 --- a/ports/esp32/port_fun.inc +++ b/ports/esp32/port_fun.inc @@ -60,6 +60,7 @@ rand, rand_r, setjmp, setlocale, +settimeofday, srand, strcasecmp, strcasestr, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy