diff --git a/examples/natmod/esp-counter/Makefile b/examples/natmod/esp-counter/Makefile new file mode 100644 index 0000000000000..19cf46b919316 --- /dev/null +++ b/examples/natmod/esp-counter/Makefile @@ -0,0 +1,35 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Espressif ESP-IDF path +IDF_PATH := /home/src/esp32/esp-idf-micropython +# Board to get correct ESP-IDF config +BOARD := GENERIC +# xtensa toolchain bin dir +PATH := $(IDF_PATH)/xtensa-esp32-elf/bin:$(PATH) + +# Name of module +MOD = espidf + +# Source files (.c or .py) +SRC = modespidf.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = xtensawin + +# Include to get the rules for compiling and linking the module +include dyn_esp32.mk +include $(MPY_DIR)/py/dynruntime.mk +CFLAGS += -std=gnu99 # override -std=c99 in dynruntime.mk +CFLAGS += -DMPY_DYN_MODULE=1 + +modespidf.c: $(MPY_DIR)/ports/esp32/plat_relo.py build/sdkconfig.h + $(ECHO) "GEN $@" + $(Q)mkdir -p build + $(Q)$< --module >$@ + +build/sdkconfig.h: $(BOARD_BUILD)/sdkconfig.h build + $(Q)cp $< $@ + +build: + $(Q)mkdir -p $@ diff --git a/examples/natmod/esp-counter/counter.py b/examples/natmod/esp-counter/counter.py new file mode 100644 index 0000000000000..02278feeb656f --- /dev/null +++ b/examples/natmod/esp-counter/counter.py @@ -0,0 +1,101 @@ +import struct, espidf + +# Directions (PCNT_COUNT_* in components/driver/include/driver/pcnt.h) +UP=1 +DOWN=2 + +# Edges +RISING=1 +FALLING=2 + +# Private constants +_COUNT_DIS = 0 +_COUNT_INC = 1 +_COUNT_DEC = 2 +_MODE_KEEP = 0 +_MODE_REVERSE = 1 +_MODE_DISABLE = 2 + +def _err_raise(err): + if err == 0: return + raise ValueError(espidf.esp_err_to_name(err)) + +class Counter: + def __init__(self, unit, pin, direction=UP, edge=RISING, limit=0, reset=True): + # check unit number + if unit < 0 or unit >= 8: + raise ValueError("unit must be in range 0..7") + self.unit = unit + # init obj + self.pin = pin + # init unit + self.init(direction, edge, limit, reset) + + def init(self, direction=UP, edge=RISING, limit=0, reset=True): + # init config elements + channel = 0 + pulse_gpio_num = self.pin + ctrl_gpio_num = -1 # not yet supported + counter_h_lim = 0 + counter_l_lim = 0 + pos_mode = _COUNT_DIS + neg_mode = _COUNT_DIS + lctrl_mode = _MODE_KEEP + hctrl_mode = _MODE_KEEP + # + self.dir_up = direction == UP + self.edges = edge + if self.dir_up: mode = _COUNT_INC + else: mode = _COUNT_DEC + # tweak config according to parameters + if edge & RISING: pos_mode = mode + if edge & FALLING: neg_mode = mode + self.limit = limit + if self.limit == 0: limit = 0x7ffff + if self.dir_up: + counter_h_lim = self.limit + else: + counter_l_lim = -self.limit + # convert pcnt_config to C struct + print('IIIIIIhhII', pulse_gpio_num, ctrl_gpio_num, + lctrl_mode, hctrl_mode, pos_mode, neg_mode, counter_h_lim, counter_l_lim, + self.unit, channel) + pcnt_config_struct = bytearray(struct.calcsize('IIIIIIhhII')) + struct.pack_into('IIIIIIhhII', pcnt_config_struct, 0, + pulse_gpio_num, ctrl_gpio_num, lctrl_mode, hctrl_mode, pos_mode, neg_mode, + counter_h_lim, counter_l_lim, self.unit, channel) + _err_raise(espidf.pcnt_unit_config(pcnt_config_struct)) + _err_raise(espidf.pcnt_counter_resume(self.unit)) # apparently it starts paused... + if reset: + _err_raise(espidf.pcnt_counter_clear(self.unit)) + + def __del__(self): + _err_raise(espidf.pcnt_counter_pause(self.unit)) + _err_raise(espidf.pcnt_intr_disable(self.unit)) + _err_raise(espidf.pcnt_set_pin(self.unit, self.channel, -1, -1)) + self.unit = -1 + self.pin = -1 + + def resume(self): + _err_raise(espidf.pcnt_unit_resume(self.unit)) + + def pause(self): + _err_raise(espidf.pcnt_unit_pause(self.unit)) + + def value(self, new_value=None): + if new_value == None: + # GET value + v_raw = bytearray(2) + _err_raise(espidf.pcnt_get_counter_value(self.unit, v_raw)) + v = struct.unpack('h', v_raw) + if not self.dir_up: + v[0] += self.limit # adjust to limit..0 interval + return v[0] + else: + # SET value + if self.dir_up and new_value != 0: + raise ValueError("only v=0 supported") + if not self.dir_up and new_value != self.limit: + raise ValueError("only v=limit supported") + _err_raise(espidf.pcnt_counter_clear(self.unit)) + return None diff --git a/examples/natmod/esp-counter/dyn_esp32.mk b/examples/natmod/esp-counter/dyn_esp32.mk new file mode 100644 index 0000000000000..14c4dfca2e43d --- /dev/null +++ b/examples/natmod/esp-counter/dyn_esp32.mk @@ -0,0 +1,239 @@ +# Select the board to build for: if not given on the command line, +# then default to GENERIC. +BOARD ?= GENERIC + +PORT_DIR := $(MPY_DIR)/ports/esp32 + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build + +BOARD_DIR ?= $(PORT_DIR)/boards/$(BOARD) +BOARD_BUILD ?= $(PORT_DIR)/build-$(BOARD) +#ifeq ($(wildcard $(BOARD_DIR)/.),) +#$(error Invalid BOARD specified: $(BOARD_DIR)) +#endif +# +#include ../../py/mkenv.mk +# +## Optional (not currently used for ESP32) +#-include mpconfigport.mk +# +#ifneq ($(SDKCONFIG),) +#$(error Use the BOARD variable instead of SDKCONFIG) +#endif + +# Expected to set SDKCONFIG +include $(BOARD_DIR)/mpconfigboard.mk +SDKCONFIG := $(addprefix $(PORT_DIR)/,$(SDKCONFIG)) + +## qstr definitions (must come before including py.mk) +#QSTR_DEFS = qstrdefsport.h +#QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h +#QSTR_GLOBAL_REQUIREMENTS = $(SDKCONFIG_H) + +#MICROPY_PY_USSL = 0 +#MICROPY_SSL_AXTLS = 0 +#MICROPY_PY_BTREE = 1 +#MICROPY_VFS_FAT = 1 +#MICROPY_VFS_LFS2 = 1 + +#FROZEN_MANIFEST ?= boards/manifest.py + +## include py core make definitions +#include $(TOP)/py/py.mk + +#GIT_SUBMODULES = lib/berkeley-db-1.xx + +#PORT ?= /dev/ttyUSB0 +#BAUD ?= 460800 +#FLASH_MODE ?= dio +#FLASH_FREQ ?= 40m +#FLASH_SIZE ?= 4MB +#CROSS_COMPILE ?= xtensa-esp32-elf- +#OBJDUMP = $(CROSS_COMPILE)objdump + +#SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined +#SDKCONFIG_H = $(BOARD_BUILD)/sdkconfig.h + +# the git hash of the currently supported ESP IDF version +ESPIDF_SUPHASH_V3 := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df +ESPIDF_SUPHASH_V4 := 463a9d8b7f9af8205222b80707f9bdbba7c530e1 + +define print_supported_git_hash +$(info Supported git hash (v3.3): $(ESPIDF_SUPHASH_V3)) +$(info Supported git hash (v4.0) (experimental): $(ESPIDF_SUPHASH_V4)) +endef + +# paths to ESP IDF and its components +ifeq ($(ESPIDF),) +ifneq ($(IDF_PATH),) +ESPIDF = $(IDF_PATH) +else +$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) +$(info See README.md for installation instructions.) +$(call print_supported_git_hash) +$(error ESPIDF not set) +endif +endif + +ESPCOMP = $(ESPIDF)/components +#ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py +ESPCOMP_KCONFIGS = $(shell find $(ESPCOMP) -name Kconfig) +ESPCOMP_KCONFIGS_PROJBUILD = $(shell find $(ESPCOMP) -name Kconfig.projbuild) + +# verify the ESP IDF version +ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) +$(info Building with ESP IDF v3) +else ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +$(info Building with ESP IDF v4) + +PYPARSING_VERSION = $(shell python3 -c 'import pyparsing; print(pyparsing.__version__)') +ifneq ($(PYPARSING_VERSION),2.3.1) +$(info ** ERROR **) +$(info EDP IDF requires pyparsing version less than 2.4) +$(info You will need to set up a Python virtual environment with pyparsing 2.3.1) +$(info Please see README.md for more information) +$(error Incorrect pyparsing version) +endif +else +$(info ** WARNING **) +$(info The git hash of ESP IDF does not match the supported version) +$(info The build may complete and the firmware may work but it is not guaranteed) +$(info ESP IDF path: $(ESPIDF)) +$(info Current git hash: $(ESPIDF_CURHASH)) +$(call print_supported_git_hash) +endif + +# pretty format of ESP IDF version, used internally by the IDF +IDF_VER := $(shell git -C $(ESPIDF) describe) + +#ifeq ($(shell which $(CC) 2> /dev/null),) +#$(info ** ERROR **) +#$(info Cannot find C compiler $(CC)) +#$(info Add the xtensa toolchain to your PATH. See README.md) +#$(error C compiler missing) +#endif + +## Support BLE by default when building with IDF 4.x. +## Can be explicitly disabled on the command line or board config. +#ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +#MICROPY_PY_BLUETOOTH ?= 1 +#ifeq ($(MICROPY_PY_BLUETOOTH),1) +#SDKCONFIG += boards/sdkconfig.ble +#MICROPY_BLUETOOTH_NIMBLE = 1 +#endif +#endif +# +# include sdkconfig to get needed configuration values +include $(SDKCONFIG) +#$(shell cp $(BOARD_BUILD)/sdkconfig* $(BUILD)) + +################################################################################ +# Compiler and linker flags + +INC_ESPCOMP += -I$(PORT_DIR) +#INC += -I$(TOP) +#INC += -I$(TOP)/lib/mp-readline +#INC += -I$(TOP)/lib/netutils +#INC += -I$(TOP)/lib/timeutils +INC_ESPCOMP += -I$(BUILD) + +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader +INC_ESPCOMP += -I$(ESPCOMP)/console +INC_ESPCOMP += -I$(ESPCOMP)/driver/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver +INC_ESPCOMP += -I$(ESPCOMP)/efuse/include +INC_ESPCOMP += -I$(ESPCOMP)/efuse/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/espcoredump/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/heap/include +INC_ESPCOMP += -I$(ESPCOMP)/log/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/include +INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_ringbuf/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_event/include +INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/lwip/src/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/ulp/include +INC_ESPCOMP += -I$(ESPCOMP)/vfs/include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include +INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include +INC_ESPCOMP += -I$(ESPCOMP)/app_update/include +INC_ESPCOMP += -I$(ESPCOMP)/pthread/include +INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include +INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +INC_ESPCOMP += -I$(ESPCOMP)/esp_common/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_eth/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_event/private_include +INC_ESPCOMP += -I$(ESPCOMP)/esp_rom/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps/sntp +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/private_include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include/esp_supplicant +INC_ESPCOMP += -I$(ESPCOMP)/xtensa/include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa/esp32/include +ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) +INC_ESPCOMP += -I$(ESPCOMP)/bt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/osi/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/btc/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/port/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ans/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/bas/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gap/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gatt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ias/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/lls/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/tps/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/util/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/ram/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/npl/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/ext/tinycrypt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/esp-hci/include +endif +else +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib +INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include +INC_ESPCOMP += -I$(ESPCOMP)/json/include +INC_ESPCOMP += -I$(ESPCOMP)/json/port/include +INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +endif + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +ifeq ($(MICROPY_PY_BLUETOOTH),1) +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 + +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) +CFLAGS_MOD += -DMICROPY_BLUETOOTH_NIMBLE=1 +endif +endif +endif + +CFLAGS = $(INC_ESPCOMP) $(CFLAGS_MOD) diff --git a/examples/natmod/esp-idf/Makefile b/examples/natmod/esp-idf/Makefile new file mode 100644 index 0000000000000..0aa05d76cca5e --- /dev/null +++ b/examples/natmod/esp-idf/Makefile @@ -0,0 +1,23 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Espressif ESP-IDF path +IDF_PATH := /home/src/esp32/esp-idf-micropython +# Board to get correct ESP-IDF config +BOARD := GENERIC +# xtensa toolchain bin dir +PATH := $(IDF_PATH)/xtensa-esp32-elf/bin:$(PATH) + +# Name of module +MOD = counter + +# Source files (.c or .py) +SRC = counter.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = xtensawin + +# Include to get the rules for compiling and linking the module +include dyn_esp32.mk +include $(MPY_DIR)/py/dynruntime.mk +CFLAGS += -std=gnu99 # override -std=c99 in dynruntime.mk diff --git a/examples/natmod/esp-idf/counter.c b/examples/natmod/esp-idf/counter.c new file mode 100644 index 0000000000000..fd8c5247a926c --- /dev/null +++ b/examples/natmod/esp-idf/counter.c @@ -0,0 +1,58 @@ +/* This example demonstrates using an ESP32 esp-idf function +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// ESP-IDF imports +#include +#include + +// This is the function which will be called from Python as counter_init(x) +STATIC mp_obj_t counter_init(mp_obj_t x_obj) { + // Extract the integer from the MicroPython input object + mp_int_t x = mp_obj_get_int(x_obj); + // Call pcnt_unit_config + pcnt_config_t cfg = { + .unit = 0, + .channel = 0, + .pulse_gpio_num = x, + .ctrl_gpio_num = -1, // not yet supported + .counter_h_lim = 0, + .counter_l_lim = 0, + .pos_mode = PCNT_COUNT_DIS, // positive edge is no-op + .neg_mode = PCNT_COUNT_DIS, // negative edge is no-op + .lctrl_mode = PCNT_MODE_KEEP, // ctrl pin is no-op + .hctrl_mode = PCNT_MODE_KEEP, // ctrl pin is no-op + }; + esp_err_t err = pcnt_unit_config(&cfg); + // Convert the result to a MicroPython integer object and return it + return mp_obj_new_int(err); +} +// Define a Python reference to the function above +STATIC MP_DEFINE_CONST_FUN_OBJ_1(counter_init_obj, counter_init); + +// Another function that calls into the firmware, this time to mp_micropython_mem_info() +// just as a simple demo which prints something to make it easy to see whether it's working or not. +STATIC mp_obj_t mem_info() { + extern int mp_micropython_mem_info(int, int); + mp_printf(&mp_plat_print, "mp_fun_table is at 0x%x\n", &mp_fun_table); + mp_printf(&mp_plat_print, "calling mp_micropython_mem_info\n"); + int i = mp_micropython_mem_info(0, 0); + mp_printf(&mp_plat_print, "mp_micropython_mem_info: %d/0x%x\n", i, i); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mem_info_obj, mem_info); + +// 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 function available in the module's namespace + mp_store_global(MP_QSTR_counter_init, MP_OBJ_FROM_PTR(&counter_init_obj)); + mp_store_global(MP_QSTR_mem_info, MP_OBJ_FROM_PTR(&mem_info_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/esp-idf/dyn_esp32.mk b/examples/natmod/esp-idf/dyn_esp32.mk new file mode 100644 index 0000000000000..5995e80090513 --- /dev/null +++ b/examples/natmod/esp-idf/dyn_esp32.mk @@ -0,0 +1,239 @@ +# Select the board to build for: if not given on the command line, +# then default to GENERIC. +BOARD ?= GENERIC + +PORT_DIR := $(MPY_DIR)/ports/esp32 + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build + +BOARD_DIR ?= $(PORT_DIR)/boards/$(BOARD) +BOARD_BUILD ?= $(PORT_DIR)/build-$(BOARD) +#ifeq ($(wildcard $(BOARD_DIR)/.),) +#$(error Invalid BOARD specified: $(BOARD_DIR)) +#endif +# +#include ../../py/mkenv.mk +# +## Optional (not currently used for ESP32) +#-include mpconfigport.mk +# +#ifneq ($(SDKCONFIG),) +#$(error Use the BOARD variable instead of SDKCONFIG) +#endif + +# Expected to set SDKCONFIG +include $(BOARD_DIR)/mpconfigboard.mk +SDKCONFIG := $(addprefix $(PORT_DIR)/,$(SDKCONFIG)) + +## qstr definitions (must come before including py.mk) +#QSTR_DEFS = qstrdefsport.h +#QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h +#QSTR_GLOBAL_REQUIREMENTS = $(SDKCONFIG_H) + +#MICROPY_PY_USSL = 0 +#MICROPY_SSL_AXTLS = 0 +#MICROPY_PY_BTREE = 1 +#MICROPY_VFS_FAT = 1 +#MICROPY_VFS_LFS2 = 1 + +#FROZEN_MANIFEST ?= boards/manifest.py + +## include py core make definitions +#include $(TOP)/py/py.mk + +#GIT_SUBMODULES = lib/berkeley-db-1.xx + +#PORT ?= /dev/ttyUSB0 +#BAUD ?= 460800 +#FLASH_MODE ?= dio +#FLASH_FREQ ?= 40m +#FLASH_SIZE ?= 4MB +#CROSS_COMPILE ?= xtensa-esp32-elf- +#OBJDUMP = $(CROSS_COMPILE)objdump + +#SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined +#SDKCONFIG_H = $(BOARD_BUILD)/sdkconfig.h + +# the git hash of the currently supported ESP IDF version +ESPIDF_SUPHASH_V3 := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df +ESPIDF_SUPHASH_V4 := 463a9d8b7f9af8205222b80707f9bdbba7c530e1 + +define print_supported_git_hash +$(info Supported git hash (v3.3): $(ESPIDF_SUPHASH_V3)) +$(info Supported git hash (v4.0) (experimental): $(ESPIDF_SUPHASH_V4)) +endef + +# paths to ESP IDF and its components +ifeq ($(ESPIDF),) +ifneq ($(IDF_PATH),) +ESPIDF = $(IDF_PATH) +else +$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) +$(info See README.md for installation instructions.) +$(call print_supported_git_hash) +$(error ESPIDF not set) +endif +endif + +ESPCOMP = $(ESPIDF)/components +#ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py +ESPCOMP_KCONFIGS = $(shell find $(ESPCOMP) -name Kconfig) +ESPCOMP_KCONFIGS_PROJBUILD = $(shell find $(ESPCOMP) -name Kconfig.projbuild) + +# verify the ESP IDF version +ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) +$(info Building with ESP IDF v3) +else ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +$(info Building with ESP IDF v4) + +PYPARSING_VERSION = $(shell python3 -c 'import pyparsing; print(pyparsing.__version__)') +ifneq ($(PYPARSING_VERSION),2.3.1) +$(info ** ERROR **) +$(info EDP IDF requires pyparsing version less than 2.4) +$(info You will need to set up a Python virtual environment with pyparsing 2.3.1) +$(info Please see README.md for more information) +$(error Incorrect pyparsing version) +endif +else +$(info ** WARNING **) +$(info The git hash of ESP IDF does not match the supported version) +$(info The build may complete and the firmware may work but it is not guaranteed) +$(info ESP IDF path: $(ESPIDF)) +$(info Current git hash: $(ESPIDF_CURHASH)) +$(call print_supported_git_hash) +endif + +# pretty format of ESP IDF version, used internally by the IDF +IDF_VER := $(shell git -C $(ESPIDF) describe) + +#ifeq ($(shell which $(CC) 2> /dev/null),) +#$(info ** ERROR **) +#$(info Cannot find C compiler $(CC)) +#$(info Add the xtensa toolchain to your PATH. See README.md) +#$(error C compiler missing) +#endif + +## Support BLE by default when building with IDF 4.x. +## Can be explicitly disabled on the command line or board config. +#ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +#MICROPY_PY_BLUETOOTH ?= 1 +#ifeq ($(MICROPY_PY_BLUETOOTH),1) +#SDKCONFIG += boards/sdkconfig.ble +#MICROPY_BLUETOOTH_NIMBLE = 1 +#endif +#endif +# +# include sdkconfig to get needed configuration values +include $(SDKCONFIG) +$(shell cp $(BOARD_BUILD)/sdkconfig* $(BUILD)) + +################################################################################ +# Compiler and linker flags + +INC_ESPCOMP += -I$(PORT_DIR) +#INC += -I$(TOP) +#INC += -I$(TOP)/lib/mp-readline +#INC += -I$(TOP)/lib/netutils +#INC += -I$(TOP)/lib/timeutils +INC_ESPCOMP += -I$(BUILD) + +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader +INC_ESPCOMP += -I$(ESPCOMP)/console +INC_ESPCOMP += -I$(ESPCOMP)/driver/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver +INC_ESPCOMP += -I$(ESPCOMP)/efuse/include +INC_ESPCOMP += -I$(ESPCOMP)/efuse/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/espcoredump/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/heap/include +INC_ESPCOMP += -I$(ESPCOMP)/log/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/include +INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_ringbuf/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_event/include +INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/lwip/src/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/ulp/include +INC_ESPCOMP += -I$(ESPCOMP)/vfs/include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include +INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include +INC_ESPCOMP += -I$(ESPCOMP)/app_update/include +INC_ESPCOMP += -I$(ESPCOMP)/pthread/include +INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include +INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +INC_ESPCOMP += -I$(ESPCOMP)/esp_common/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_eth/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_event/private_include +INC_ESPCOMP += -I$(ESPCOMP)/esp_rom/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps/sntp +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/private_include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include/esp_supplicant +INC_ESPCOMP += -I$(ESPCOMP)/xtensa/include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa/esp32/include +ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) +INC_ESPCOMP += -I$(ESPCOMP)/bt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/osi/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/btc/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/common/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/port/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ans/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/bas/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gap/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gatt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ias/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/lls/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/tps/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/util/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/ram/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/npl/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/ext/tinycrypt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/esp-hci/include +endif +else +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib +INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include +INC_ESPCOMP += -I$(ESPCOMP)/json/include +INC_ESPCOMP += -I$(ESPCOMP)/json/port/include +INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +endif + +ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) +ifeq ($(MICROPY_PY_BLUETOOTH),1) +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 + +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) +CFLAGS_MOD += -DMICROPY_BLUETOOTH_NIMBLE=1 +endif +endif +endif + +CFLAGS = $(INC_ESPCOMP) $(CFLAGS_MOD) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index fe4787b7ae338..ef826ea64e438 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -761,20 +761,30 @@ APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp endif APP_LD_ARGS += $(OBJ) APP_LD_ARGS += $(LIB) +APP_LD_ARGS += $(BUILD)/plat_relo.o APP_LD_ARGS += --end-group $(BUILD)/esp32_out.ld: $(SDKCONFIG_H) $(Q)$(CC) -I$(BUILD) -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@ -$(BUILD)/application.bin: $(BUILD)/application.elf +$(BUILD)/application.bin: $(BUILD)/application.elf $(BUILD)/application.sym $(ECHO) "Create $@" $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< -$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.project.ld +# Memory map produced by nm, for troubleshooting purposes, not required for operation +$(BUILD)/application.sym: $(BUILD)/application.elf + $(ECHO) "Create $@" + $(Q)xtensa-esp32-elf-nm -l -n $< >$@ + +$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.project.ld $(BUILD)/plat_relo.o $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) $(Q)$(SIZE) $@ +$(BUILD)/plat_relo.s: plat_relo.py + $(ECHO) "GEN platform relocations" + $(Q)./plat_relo.py --tab >$@ + define compile_cxx $(ECHO) "CXX $<" $(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $< diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index bca68538b13db..236866f9e4a33 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -162,6 +162,7 @@ #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) #define MICROPY_PY_BLUETOOTH_DEFAULT_NAME ("ESP32") +#define MICROPY_PY_PLAT_RELO (1) // fatfs configuration #define MICROPY_FATFS_ENABLE_LFN (1) @@ -191,6 +192,7 @@ extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_network; extern const struct _mp_obj_module_t mp_module_onewire; + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \ diff --git a/ports/esp32/plat_relo.py b/ports/esp32/plat_relo.py new file mode 100755 index 0000000000000..398a500ecf89f --- /dev/null +++ b/ports/esp32/plat_relo.py @@ -0,0 +1,116 @@ +#! /usr/bin/python3 + +# Linking table for platform-specific functions. +# +# The entry points below list a number of functions in the MP firmware that are to be exposed to +# native modules. This is typically used to expose ESP-IDF functions so they can be called directly +# from C code in dynamically loaded native modules. The native module can then #include the esp-idf +# header files as usual and call the functions normally. + +# TODO: this needs to be loaded from a file, not hard-coded here +entry_points = [ + ("esp_chip_info", "P", ""), + ("esp_get_idf_version", "", "s"), + ("esp_err_to_name", "I", "s"), + ("pcnt_unit_config", "P", "I"), + ("pcnt_get_counter_value", "IP", "I"), + ("pcnt_counter_pause", "I", "I"), + ("pcnt_counter_resume", "I", "I"), + ("pcnt_counter_clear", "I", "I"), + ("pcnt_intr_disable", "I", "I"), + ] + +imports = [ + "esp_err.h", + "esp_idf_version.h", + "esp_system.h", + "driver/pcnt.h", + ] + +type_map = { "I": "uint", "i": "int", "H": "uint16", "h": "int16", "B": "uint8", "b": "int8", + "P": "void*", "s": "char*", "": "void" } + +return_map = { "I": "mp_obj_new_int({})", "s": "mp_obj_new_str({0}, strlen({0}))", "": "{}" } + +import sys + +if len(sys.argv) > 1 and sys.argv[1] == '--tab': + # Generate platform relocation table compiled into the MP firmware + print('\t.file\t"plat_relo.py"') + print('\t.section\t.rodata.plat_relo_tab,"a",@progbits') + print('\t.align\t4') + print('\t.global\tplat_relo_tab') + print('\t.type\tplat_relo_tab, @object') + print('plat_relo_tab:') + for name, _, _ in entry_points: + print('\t.word\t' + name) + print('\t.size\tplat_relo_tab, .-plat_relo_tab') + +elif len(sys.argv) > 1 and (sys.argv[1] == '--module' or sys.argv[1] == '--builtin'): + # Generate espidf module to expose functions to python + builtin = sys.argv[1] == '--builtin' + print('#include ') + print('#include ') + if builtin: + print('#include "py/runtime.h"') + else: + print('#include "py/dynruntime.h"') + + print('// ESP-IDF imports') + for im in imports: + print("#include <{}>".format(im)) + for name, args, res in entry_points: + print() + print("STATIC mp_obj_t espidf_{}(".format(name), end='') + print(", ".join(["mp_obj_t arg{}".format(ix) for ix in range(len(args))]), end='') + print(") {") + for ix, fmt in enumerate(args): + print("\t// convert arg{}".format(ix)) + if fmt == "P": + print("\tmp_buffer_info_t val{}_buf;".format(ix)) + print("\tmp_get_buffer_raise(arg{0}, &val{0}_buf, MP_BUFFER_RW);".format(ix)) + print("\tvoid *val{0} = (void *)(val{0}_buf.buf);".format(ix)) + + elif fmt in frozenset(["I", "i", "H", "h", "B", "b"]): + print("\t{1} val{0} = ({1})mp_obj_get_int(arg{0});".format(ix, type_map[fmt])) + print("\t// call") + if res == "": + print("\tmp_obj_t ret = mp_const_none;") + print("\t{}(".format(name), end='') + else: + print("\tconst {} ret = {}(".format(type_map[res], name), end='') + print(", ".join([ "val{}".format(ix) for ix in range(len(args)) ]), end='') + print(");") + print("\treturn " + return_map[res].format('ret') + ";\n}") + if len(args) < 4: + print("STATIC MP_DEFINE_CONST_FUN_OBJ_{}(espidf_{}_obj, espidf_{});".format( + len(args), name, name)) + else: + print("STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espidf_{}_obj, {}, {}, espidf_{});".format( + len(args), len(args), name, name)) + print() + if sys.argv[1] == '--builtin': + # generate module built into the firmware + print("STATIC const mp_rom_map_elem_t mp_module_espidf_globals_table[] = {") + print("\t{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espidf) },") + for name, _, _ in entry_points: + print("\t{{ MP_ROM_QSTR(MP_QSTR_{}), MP_ROM_PTR(&espidf_{}) }},".format(name, name)) + print('''\ +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_espidf_globals, mp_module_espidf_globals_table); + +const mp_obj_module_t mp_module_espidf = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_espidf_globals, +}; + +#endif +''', end='') + else: + # generate dynamically loadable module + print("mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {") + print("\tMP_DYNRUNTIME_INIT_ENTRY") + for name, _, _ in entry_points: + print("\tmp_store_global(MP_QSTR_{0}, MP_OBJ_FROM_PTR(&espidf_{0}_obj));".format(name)) + print("\tMP_DYNRUNTIME_INIT_EXIT") + print("}") diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 8b65745afdf78..9b459cf6a7a64 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -128,6 +128,11 @@ $(BUILD)/%.o: %.c $(CONFIG_H) Makefile $(ECHO) "CC $<" $(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $< +# Build .o from .s source files +%.o: %.s $(CONFIG_H) Makefile + $(ECHO) "AS $<" + $(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $< + # Build .mpy from .py source files $(BUILD)/%.mpy: %.py $(ECHO) "MPY $<" diff --git a/py/persistentcode.c b/py/persistentcode.c index 7039f9f57a3c6..4369df831fbf9 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -189,12 +189,16 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { #endif } +extern size_t plat_relo_tab[]; + void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) { // Relocate native code reloc_info_t *ri = ri_in; uint8_t op; uintptr_t *addr_to_adjust = NULL; while ((op = read_byte(ri->reader)) != 0xff) { + mp_printf(&mp_plat_print, "mp_native_relocate %d\n", op); + // if lsb==1 then an offset follows the op byte, else addr_to_adjust auto-increments if (op & 1) { // Point to new location to make adjustments size_t addr = read_uint(ri->reader, NULL); @@ -225,14 +229,20 @@ 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) { + size_t index = read_uint(ri->reader, NULL); + dest = ((uintptr_t*)&plat_relo_tab)[index]; + mp_printf(&mp_plat_print, "mp_native_relocate: op=%d, index=%d, dest=0x%08x\n", op, index, dest); } else { // Destination is an entry in mp_fun_table dest = ((uintptr_t*)&mp_fun_table)[op - 7]; + mp_printf(&mp_plat_print, "mp_native_relocate: op=%d, dest=0x%08x\n", op, dest); } while (n--) { *addr_to_adjust++ += dest; } } + mp_printf(&mp_plat_print, "mp_native_relocate DONE\n"); } #endif diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 31c3912991c48..bd11b164c0ff3 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -34,6 +34,26 @@ sys.path.append(os.path.dirname(__file__) + '/../py') import makeqstrdata as qstrutil +# Platform-specific relocation table, which contains the addresses of a number of platform specific +# functions compiled into the firmware. These entries are used by the dynamic linker to fix-up +# relocation entries in dynamically loaded mpy modules. +# TODO: this needs to be loaded from a file, not hard-coded here. +plat_relo_entries = { name : idx + for idx, name in enumerate([ + "esp_chip_info", + "esp_get_idf_version", + "esp_err_to_name", + "pcnt_unit_config", + "pcnt_get_counter_value", + "pcnt_counter_pause", + "pcnt_counter_resume", + "pcnt_counter_clear", + "pcnt_intr_disable", + "mp_micropython_mem_info", + "strlen", + ]) +} + # MicroPython constants MPY_VERSION = 5 MP_NATIVE_ARCH_X86 = 1 @@ -256,6 +276,10 @@ def isrodata(self): def isbss(self): return self.sec_name.startswith('.bss') + def __repr__(self): # for debugging purposes + keys = ['name', 'sym', 'offset', 'link_addr', 'sec_name'] + return "GOTEntry(" + repr({ k:getattr(self, k) for k in keys}) + ")" + class LiteralEntry: def __init__(self, value, offset): self.value = value @@ -381,8 +405,11 @@ def populate_got(env): dest = '.data.rel.ro' elif got_entry.sec_name.startswith('.bss'): dest = '.bss' + elif got_entry.sec_name == '.external.plat_relo_tab': + dest = 1000+got_entry.sym.plat_relo_offset + print("GOT entry: {}->{} ({})".format(got_entry.name, dest, repr(got_entry))) else: - assert 0, (got_entry.name, got_entry.sec_name) + assert 0, repr(got_entry) env.mpy_relocs.append(('.text', env.got_section.addr + got_entry.offset, dest)) # Print out the final GOT @@ -680,6 +707,7 @@ def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): 'mp_stream_write_obj', ]) } + plat_relo_sec = Section('.external.plat_relo_tab', b'', 0) for sym in env.unresolved_syms: assert sym['st_value'] == 0 if sym.name == '_GLOBAL_OFFSET_TABLE_': @@ -692,12 +720,15 @@ 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 plat_relo_entries: + sym.section = plat_relo_sec + sym.plat_relo_offset = plat_relo_entries[sym.name] + print("Unresolved: {} -> plat_relo_sec+{}".format(sym.name, sym.plat_relo_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 @@ -766,12 +797,29 @@ 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 plat_relo_tab. + - 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 + index = None if dest <= 2: dest = (dest << 1) | (n > 1) + elif dest >= 1000: + # offset into plat_relo_tab + assert dest < 1000+65536 + index = dest-1000 + dest = 126 + print("write_reloc plat_relo_tab+{}".format(index)) else: - assert 6 <= dest <= 127 + assert 6 <= dest < 126 assert n == 1 dest = dest << 1 | need_offset assert 0 <= dest <= 0xfe, dest @@ -782,6 +830,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) @@ -865,8 +915,14 @@ 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, int): + if kind < 1000: + # element of mp_fun_table + kind = 7 + kind + else: # element of plat_relo_tab + 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: 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