diff --git a/contrib/loaders/flash/esp/esp32/Makefile b/contrib/loaders/flash/esp/esp32/Makefile index 01560ae7d1..efdd57adb2 100644 --- a/contrib/loaders/flash/esp/esp32/Makefile +++ b/contrib/loaders/flash/esp/esp32/Makefile @@ -36,15 +36,16 @@ STUB_CHIP := ESP32 SRCS := $(IDF_PATH)/components/esp_hw_support/port/esp32/rtc_clk.c \ $(IDF_PATH)/components/esp_hw_support/port/esp32/rtc_clk_init.c \ $(IDF_PATH)/components/esp_hw_support/port/esp32/rtc_time.c \ - $(IDF_PATH)/components/spi_flash/esp32/spi_flash_rom_patch.c + $(IDF_PATH)/components/spi_flash/esp32/spi_flash_rom_patch.c \ + $(IDF_PATH)/components/xtensa/eri.c -CFLAGS := +CFLAGS := -mlongcalls -mtext-section-literals INCLUDES := -I$(IDF_PATH)/components/esp32/include -I$(IDF_PATH)/components/soc/esp32/include \ -I$(IDF_PATH)/components/esp_rom/include/esp32 -I$(IDF_PATH)/components/xtensa/esp32/include \ -I$(IDF_PATH)/components/hal/esp32/include -I$(IDF_PATH)/components/esp_hw_support/port/esp32/private_include \ - -I$(IDF_PATH)/components/spi_flash/include - + -I$(IDF_PATH)/components/xtensa/include -I$(IDF_PATH)/components/freertos/port/xtensa/include + DEFINES := LDFLAGS := -L$(IDF_PATH)/components/esp32/ld -T$(IDF_PATH)/components/esp_rom/esp32/ld/esp32.rom.ld \ diff --git a/contrib/loaders/flash/esp/esp32/stub_flasher_chip.h b/contrib/loaders/flash/esp/esp32/stub_flasher_chip.h index 9f1c0c7d07..92b7e5c287 100644 --- a/contrib/loaders/flash/esp/esp32/stub_flasher_chip.h +++ b/contrib/loaders/flash/esp/esp32/stub_flasher_chip.h @@ -47,4 +47,8 @@ struct stub_flash_state { void stub_flash_state_prepare(struct stub_flash_state *state); void stub_flash_state_restore(struct stub_flash_state *state); +uint32_t stub_esp_clk_cpu_freq(void); + +#include "stub_xtensa_chips.h" + #endif /*ESP32_FLASHER_STUB_H */ diff --git a/contrib/loaders/flash/esp/esp32_s2/Makefile b/contrib/loaders/flash/esp/esp32_s2/Makefile index ce3876b2ca..c98b8d7c2e 100644 --- a/contrib/loaders/flash/esp/esp32_s2/Makefile +++ b/contrib/loaders/flash/esp/esp32_s2/Makefile @@ -36,15 +36,17 @@ STUB_CHIP := ESP32_S2 SRCS := $(IDF_PATH)/components/esp_hw_support/port/esp32s2/rtc_clk.c \ $(IDF_PATH)/components/esp_hw_support/port/esp32s2/rtc_clk_init.c \ $(IDF_PATH)/components/esp_hw_support/port/esp32s2/rtc_time.c \ - $(IDF_PATH)/components/esp_hw_support/port/esp32s2/regi2c_ctrl.c + $(IDF_PATH)/components/esp_hw_support/port/esp32s2/regi2c_ctrl.c \ + $(IDF_PATH)/components/xtensa/eri.c -CFLAGS := +CFLAGS := -mlongcalls -mtext-section-literals INCLUDES := -I$(IDF_PATH)/components/esp32s2/include -I$(IDF_PATH)/components/soc/esp32s2/include \ -I$(IDF_PATH)/components/esp_rom/include/esp32s2 -I$(IDF_PATH)/components/xtensa/esp32s2/include \ -I$(IDF_PATH)/components/hal/esp32s2/include -I$(IDF_PATH)/components/esp_hw_support/port/esp32s2/private_include \ - -I$(IDF_PATH)/components/spi_flash/include -I$(IDF_PATH)/components/esp_hw_support/port/esp32s2 - + -I$(IDF_PATH)/components/esp_hw_support/port/esp32s2 \ + -I$(IDF_PATH)/components/xtensa/include -I$(IDF_PATH)/components/freertos/port/xtensa/include + DEFINES := LDFLAGS := -L$(IDF_PATH)/components/esp32s2/ld -T$(IDF_PATH)/components/esp_rom/esp32s2/ld/esp32s2.rom.ld \ diff --git a/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.c b/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.c index 4acb882974..ca95f46008 100644 --- a/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.c +++ b/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.c @@ -34,6 +34,7 @@ #include "stub_rom_chip.h" #include "stub_flasher_int.h" #include "stub_flasher_chip.h" +#include "stub_xtensa_chips.h" uint32_t g_stub_cpu_freq_hz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * MHZ; diff --git a/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.h b/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.h index 3c14429b89..43093dc851 100644 --- a/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.h +++ b/contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.h @@ -36,4 +36,8 @@ struct stub_flash_state { void stub_flash_state_prepare(struct stub_flash_state *state); void stub_flash_state_restore(struct stub_flash_state *state); +uint32_t stub_esp_clk_cpu_freq(void); + +#include "stub_xtensa_chips.h" + #endif /*ESP32_S2_FLASHER_STUB_H */ diff --git a/contrib/loaders/flash/esp/esp32c3/Makefile b/contrib/loaders/flash/esp/esp32c3/Makefile new file mode 100644 index 0000000000..ebc99e5445 --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/Makefile @@ -0,0 +1,56 @@ +# Makefile to compile the flasher stub program +# +# Note that YOU DO NOT NEED TO COMPILE THIS IN ORDER TO JUST USE + +# See the comments in the top of the Makefile for parameters that +# you probably want to override. +# +# Copyright (c) 2017 Espressif Systems +# All rights reserved +# +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +# Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Prefix for ESP32-S2 cross compilers (can include a directory path) +CROSS ?= riscv32-esp-elf- + +# Path to the esp-idf root dir +IDF_PATH ?= ../.. + +STUB_CHIP_PATH := $(shell pwd) +STUB_COMMON_PATH := $(STUB_CHIP_PATH)/.. +STUB_OBJ_DEPS := sdkconfig.h +STUB_LD_SCRIPT := stub.ld +STUB_CHIP := ESP32C3 + +SRCS := $(IDF_PATH)/components/esp_hw_support/port/esp32c3/rtc_clk_init.c \ + $(IDF_PATH)/components/esp_hw_support/port/esp32c3/rtc_clk.c \ + $(IDF_PATH)/components/esp_hw_support/port/esp32c3/rtc_time.c \ + $(IDF_PATH)/components/esp_hw_support/regi2c_ctrl.c \ + $(IDF_PATH)/components/app_trace/port/riscv/port.c + +CFLAGS := + +INCLUDES := -I$(IDF_PATH)/components/soc/esp32c3/include -I$(IDF_PATH)/components/riscv/include \ + -I$(IDF_PATH)/components/hal/esp32c3/include -I$(IDF_PATH)/components/esp32c3/include \ + -I$(IDF_PATH)/components/esp_hw_support/port/esp32c3/private_include -I$(IDF_PATH)/components/esp_rom/include/esp32c3 \ + -I$(IDF_PATH)/components/esp_hw_support/port/esp32c3 \ + -I$(IDF_PATH)/components/freertos/include \ + -I$(IDF_PATH)/components/freertos/port/riscv/include + +DEFINES := + +LDFLAGS += -T$(IDF_PATH)/components/esp_rom/esp32c3/ld/esp32c3.rom.ld -T$(IDF_PATH)/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld \ + -T$(IDF_PATH)/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld + +include ../stub_common.mk diff --git a/contrib/loaders/flash/esp/esp32c3/sdkconfig.h b/contrib/loaders/flash/esp/esp32c3/sdkconfig.h new file mode 100644 index 0000000000..9aef26c6b8 --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/sdkconfig.h @@ -0,0 +1,33 @@ +#ifndef _STUB_SDKCONFIG_H_ +#define _STUB_SDKCONFIG_H_ + +#define CONFIG_IDF_TARGET_ARCH_RISCV 1 +#define CONFIG_IDF_TARGET_ESP32C3 1 +#define CONFIG_FREERTOS_UNICORE 1 +/* Use ROM flash driver patch + * #define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 + * Disable application module multi-threading lock */ +#define CONFIG_APPTRACE_LOCK_ENABLE 0 +/* Enable apptarce module for flash data transfers */ +#define CONFIG_APPTRACE_DEST_JTAG 1 +#define CONFIG_APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE 1 +#define CONFIG_APPTRACE_ENABLE 1 +#define CONFIG_APPTRACE_BUF_SIZE 16384 +#define CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX 0 +/* Debug UART number */ +#define CONFIG_CONSOLE_UART_NUM 0 +/* Debug UART baudrate */ +#define CONFIG_CONSOLE_UART_BAUDRATE 115200 +/* alloc apptrace data buffers on stack */ +#define CONFIG_STUB_STACK_DATA_POOL_SIZE (2*CONFIG_APPTRACE_BUF_SIZE) + +/* needed due to apptrace sources usage */ +#define CONFIG_LOG_MAXIMUM_LEVEL 0 +/* needed due to various checks in IDF headers */ +#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16 +/* TODO: use current clk, get it from PLL settings */ +#define CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ 160 +/* Unused by stub, just for compilation of IDF */ +#define CONFIG_PARTITION_TABLE_OFFSET 0x8000 + +#endif /*_STUB_SDKCONFIG_H_ */ diff --git a/contrib/loaders/flash/esp/esp32c3/stub.ld b/contrib/loaders/flash/esp/esp32c3/stub.ld new file mode 100644 index 0000000000..6e7a5d77ed --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub.ld @@ -0,0 +1,29 @@ +/*************************************************************************** + * LD script for ESP32-S2 flassher stub * + * Copyright (C) 2019 Espressif Systems Ltd. * + * Author: Alexey Gerenkov * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +MEMORY { + /* place stub at the beginning of the OpenOCD working area, + remaining space will be used for other chunks */ + iram : org = 0x40380000, len = 0x4000 + dram : org = 0x3FC84000, len = 0xC000 +} + +INCLUDE stub_common.ld diff --git a/contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.c b/contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.c new file mode 100644 index 0000000000..0f566d4a8d --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.c @@ -0,0 +1,384 @@ +/*************************************************************************** + * ESP32-C3 specific flasher stub functions * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "sdkconfig.h" +#include "soc/rtc.h" +#include "soc/spi_mem_reg.h" +#include "soc/gpio_reg.h" +#include "rtc_clk_common.h" +#include "esp_app_trace_membufs_proto.h" +#include "stub_rom_chip.h" +#include "stub_flasher_int.h" +#include "stub_flasher_chip.h" +#include "stub_flasher.h" + + +#define ESP_APPTRACE_RISCV_BLOCK_LEN_MSK 0x7FFFUL +#define ESP_APPTRACE_RISCV_BLOCK_LEN(_l_) ((_l_) & ESP_APPTRACE_RISCV_BLOCK_LEN_MSK) +#define ESP_APPTRACE_RISCV_BLOCK_LEN_GET(_v_) ((_v_) & ESP_APPTRACE_RISCV_BLOCK_LEN_MSK) +#define ESP_APPTRACE_RISCV_BLOCK_ID_MSK 0x7FUL +#define ESP_APPTRACE_RISCV_BLOCK_ID(_id_) (((_id_) & ESP_APPTRACE_RISCV_BLOCK_ID_MSK) << 15) +#define ESP_APPTRACE_RISCV_BLOCK_ID_GET(_v_) (((_v_) >> 15) & ESP_APPTRACE_RISCV_BLOCK_ID_MSK) +#define ESP_APPTRACE_RISCV_HOST_DATA (1 << 22) +#define ESP_APPTRACE_RISCV_HOST_CONNECT (1 << 23) + +/** RISCV memory host iface control block */ +typedef struct { + uint32_t ctrl; + /* - Guard field. If this register is not zero then CPU is changing this struct and */ + /* this guard field holds address of the instruction which application will execute when + * CPU finishes with those modifications. */ + uint32_t stat; + esp_apptrace_mem_block_t *mem_blocks; +} esp_apptrace_riscv_ctrl_block_t; + + +static esp_apptrace_riscv_ctrl_block_t *s_apptrace_ctrl; +#if CONFIG_STUB_STACK_DATA_POOL_SIZE > 0 +static uint8_t *s_stack_data_pool; +static size_t s_stack_data_pool_sz; +#endif + +uint32_t g_stub_cpu_freq_hz = CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ * MHZ; + + +void vPortEnterCritical(void) +{ +} + +void vPortExitCritical(void) +{ +} + +static void esp32c3_flash_disable_cache(uint32_t *saved_state) +{ + uint32_t icache_state; + icache_state = Cache_Suspend_ICache() << 16; + saved_state[0] = icache_state; +} + +static void esp32c3_flash_restore_cache(uint32_t *saved_state) +{ + Cache_Resume_ICache(saved_state[0] >> 16); +} + +uint32_t stub_flash_get_id(void) +{ + uint32_t ret; + + STUB_LOGD("flash %x, cs %x, bs %x, ss %x, ps %x, sm %x\n", + rom_spiflash_legacy_data->chip.device_id, + rom_spiflash_legacy_data->chip.chip_size, + rom_spiflash_legacy_data->chip.block_size, + rom_spiflash_legacy_data->chip.sector_size, + rom_spiflash_legacy_data->chip.page_size, + rom_spiflash_legacy_data->chip.status_mask); + WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0, 0);/* clear regisrter */ + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_MEM_FLASH_RDID); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0) ; + ret = READ_PERI_REG(PERIPHS_SPI_FLASH_C0) & 0xffffff; + STUB_LOGD("Flash ID read %x\n", ret); + return ret >> 16; +} + +void stub_flash_cache_flush(void) +{ + /* we do not know breakpoint program address here, so invalidate the + * whole ICache */ + Cache_Invalidate_ICache_All(); +} + +void stub_flash_state_prepare(struct stub_flash_state *state) +{ + uint32_t spiconfig = ets_efuse_get_spiconfig(); + uint32_t strapping = REG_READ(GPIO_STRAP_REG); + /* If GPIO1 (U0TXD) is pulled low and flash pin configuration is not set in efuse, assume + * HSPI flash mode (same as normal boot) */ + if (spiconfig == 0 && (strapping & 0x1c) == 0x08) + spiconfig = 1; /* HSPI flash mode */ + + esp32c3_flash_disable_cache(state->cache_flags); + esp_rom_spiflash_attach(spiconfig, 0); +} + +void stub_flash_state_restore(struct stub_flash_state *state) +{ + esp32c3_flash_restore_cache(state->cache_flags); +} + +#define RTC_PLL_FREQ_320M 320 +#define RTC_PLL_FREQ_480M 480 + +rtc_xtal_freq_t stub_rtc_clk_xtal_freq_get(void) +{ + uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG); + if (!clk_val_is_valid(xtal_freq_reg)) + return RTC_XTAL_FREQ_40M; + return reg_val_to_clk_val(xtal_freq_reg); +} + +/* Obviously we can call rtc_clk_cpu_freq_get_config() from esp-idf +But this call may cause undesired locks due to ets_printf or abort +*/ +int stub_rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) +{ + rtc_cpu_freq_src_t source; + uint32_t source_freq_mhz; + uint32_t div; + uint32_t freq_mhz; + uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL); + switch (soc_clk_sel) { + case DPORT_SOC_CLK_SEL_XTAL: { + source = RTC_CPU_FREQ_SRC_XTAL; + div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1; + source_freq_mhz = (uint32_t) stub_rtc_clk_xtal_freq_get(); + freq_mhz = source_freq_mhz / div; + } + break; + case DPORT_SOC_CLK_SEL_PLL: { + source = RTC_CPU_FREQ_SRC_PLL; + uint32_t cpuperiod_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, + SYSTEM_CPUPERIOD_SEL); + uint32_t pllfreq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, + SYSTEM_PLL_FREQ_SEL); + source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M; + if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) { + div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4; + freq_mhz = 80; + } else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) { + div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2; + div = 3; + freq_mhz = 160; + } else { + /* unsupported frequency configuration */ + return -1; + } + break; + } + case DPORT_SOC_CLK_SEL_8M: + source = RTC_CPU_FREQ_SRC_8M; + source_freq_mhz = 8; + div = 1; + freq_mhz = source_freq_mhz; + break; + default: + /* unsupported frequency configuration */ + return -2; + } + *out_config = (rtc_cpu_freq_config_t) { + .source = source, + .source_freq_mhz = source_freq_mhz, + .div = div, + .freq_mhz = freq_mhz + }; + return 0; +} + +/* this function has almost the same implementation for ESP32 and ESP32-S2 + * TODO: move to common file */ +int stub_cpu_clock_configure(int cpu_freq_mhz) +{ + rtc_cpu_freq_config_t old_config; + int ret = stub_rtc_clk_cpu_freq_get_config(&old_config); + if (ret < 0) { + /* this return value will avoid undesired restore requests for unsupported frequency + *configuration */ + old_config.freq_mhz = 0; + } + +#if STUB_LOG_LOCAL_LEVEL > STUB_LOG_NONE + uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); +#endif + + /* set to maximum possible value */ + if (cpu_freq_mhz == -1) + cpu_freq_mhz = CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ; + + /* Set CPU to configured value. Keep other clocks unmodified. */ + if (cpu_freq_mhz > 0) { + rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT(); + /* ESP32-S2 doesn't have XTAL_FREQ choice, always 40MHz. + So using default value is fine */ + clk_cfg.cpu_freq_mhz = cpu_freq_mhz; + clk_cfg.slow_freq = rtc_clk_slow_freq_get(); + clk_cfg.fast_freq = rtc_clk_fast_freq_get(); + rtc_clk_init(clk_cfg); + + g_stub_cpu_freq_hz = cpu_freq_mhz * MHZ; + } + + return old_config.freq_mhz; +} + +#if STUB_LOG_LOCAL_LEVEL > STUB_LOG_NONE +void stub_uart_console_configure() +{ + extern bool g_uart_print; + /* set the default parameter to UART module, but don't enable RX interrupt */ + uartAttach(NULL); + /* first enable uart0 as printf channel */ + uint32_t clock = ets_get_apb_freq(); + ets_update_cpu_frequency(clock/1000000); + + Uart_Init(ets_efuse_get_uart_print_channel(), UART_CLK_FREQ_ROM); + /* install to print later + * Non-Flash Boot can print + * Flash Boot can print when RTC_CNTL_STORE4_REG bit0 is 0 (can be 1 after deep sleep, software reset) and printf boot. + * print boot determined by GPIO and efuse, see ets_is_print_boot + */ + g_uart_print = true; + ets_install_uart_printf(); +} +#endif + +uint32_t stub_esp_clk_cpu_freq(void) +{ + return (CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ * 1000000); +} + +/* override apptrace control block advertising func, IDF's implementation issues syscall */ +int esp_apptrace_advertise_ctrl_block(void *ctrl_block_addr) +{ + s_apptrace_ctrl = ctrl_block_addr; + return 0; +} + +#if CONFIG_STUB_STACK_DATA_POOL_SIZE > 0 +void stub_stack_data_pool_init(uint8_t *data, size_t sz) +{ + STUB_LOGD("stack data pool %lu bytes @ 0x%x\n", sz, data); + s_stack_data_pool = data; + s_stack_data_pool_sz = sz; +} + +void esp_apptrace_get_up_buffers(esp_apptrace_mem_block_t mem_blocks_cfg[2]) +{ + /* use whole stack data pool for apptrace up buffers */ + mem_blocks_cfg[0].start = s_stack_data_pool; + mem_blocks_cfg[0].sz = s_stack_data_pool_sz / 2; + mem_blocks_cfg[1].start = s_stack_data_pool + mem_blocks_cfg[0].sz; + mem_blocks_cfg[1].sz = mem_blocks_cfg[0].sz; +} +#endif + +int stub_apptrace_prepare() +{ + /* imply that host is auto-connected */ + s_apptrace_ctrl->ctrl |= ESP_APPTRACE_RISCV_HOST_CONNECT; + return ESP_STUB_ERR_OK; +} + +int64_t esp_timer_get_time(void) +{ + /* this function is used by apptrace code to implement timeouts. + unfortunately esp32c3 does not support CPU cycle counter, so we have two options: + 1) Use some HW timer. It can be hard, because we need to ensure that it is initialized and possibly restore its state. + 2) Emulate timer by incrementing some var on every call. + Stub flasher uses ESP_APPTRACE_TMO_INFINITE only, so this function won't be called by apptrace at all. */ + return 0; +} + +uint64_t stub_get_time(void) +{ + /* this function is used for perf measurements only. + unfortunately esp32c3 does not support CPU cycle counter and usage of HW timer is problematic */ + return 0; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_area(uint32_t start_addr, uint32_t area_len) +{ + int32_t total_sector_num; + int32_t head_sector_num; + uint32_t sector_no; + uint32_t sector_num_per_block; + + /* set read mode to Fastmode ,not QDIO mode for erase + * + * TODO: this is probably a bug as it doesn't re-enable QIO mode, not serious as this + * function is not used in IDF. + * esp_rom_spiflash_config_readmode(ESP_ROM_SPIFLASH_SLOWRD_MODE); */ + + /* check if area is oversize of flash */ + if ((start_addr + area_len) > rom_spiflash_legacy_data->chip.chip_size) + return ESP_ROM_SPIFLASH_RESULT_ERR; + + /* start_addr is aligned as sector boundary */ + if (0 != (start_addr % rom_spiflash_legacy_data->chip.sector_size)) + return ESP_ROM_SPIFLASH_RESULT_ERR; + + /* Unlock flash to enable erase */ + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_unlock(/*&rom_spiflash_legacy_data->chip*/)) + return ESP_ROM_SPIFLASH_RESULT_ERR; + + sector_no = start_addr / rom_spiflash_legacy_data->chip.sector_size; + sector_num_per_block = rom_spiflash_legacy_data->chip.block_size / + rom_spiflash_legacy_data->chip.sector_size; + total_sector_num = + (0 == + (area_len % + rom_spiflash_legacy_data->chip.sector_size)) ? area_len / + rom_spiflash_legacy_data->chip.sector_size : + 1 + (area_len / rom_spiflash_legacy_data->chip.sector_size); + + /* check if erase area reach over block boundary */ + head_sector_num = sector_num_per_block - (sector_no % sector_num_per_block); + + head_sector_num = + (head_sector_num >= total_sector_num) ? total_sector_num : head_sector_num; + + /* JJJ, BUG of 6.0 erase + * middle part of area is aligned by blocks */ + total_sector_num -= head_sector_num; + + /* head part of area is erased */ + while (0 != head_sector_num) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_sector(sector_no)) + return ESP_ROM_SPIFLASH_RESULT_ERR; + sector_no++; + head_sector_num--; + } + while (total_sector_num > sector_num_per_block) { + if (ESP_ROM_SPIFLASH_RESULT_OK != + esp_rom_spiflash_erase_block(sector_no / sector_num_per_block)) + return ESP_ROM_SPIFLASH_RESULT_ERR; + sector_no += sector_num_per_block; + total_sector_num -= sector_num_per_block; + } + + /* tail part of area burn */ + while (0 < total_sector_num) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_sector(sector_no)) + return ESP_ROM_SPIFLASH_RESULT_ERR; + sector_no++; + total_sector_num--; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +bool esp_cpu_in_ocd_debug_mode(void) +{ + return true; +} + +int stub_flash_read_buff(uint32_t addr, void *buffer, uint32_t size) +{ + return esp_rom_spiflash_read(addr, buffer, size); +} diff --git a/contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.h b/contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.h new file mode 100644 index 0000000000..70f1cfd24a --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * ESP32-S2 flasher stub definitions * + * Copyright (C) 2019 Espressif Systems Ltd. * + * Author: Alexey Gerenkov * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ +#ifndef ESP32C3_FLASHER_STUB_H +#define ESP32C3_FLASHER_STUB_H + +#include "sdkconfig.h" + +#define STUB_FLASH_SECTOR_SIZE 0x1000 +/* Flash geometry constants */ +#define STUB_FLASH_BLOCK_SIZE 0x10000 +#define STUB_FLASH_PAGE_SIZE 0x100 +#define STUB_FLASH_STATUS_MASK 0xFFFF + +struct stub_flash_state { + uint32_t cache_flags[2]; +}; + +#define ESP_APPTRACE_USR_DATA_LEN_MAX (CONFIG_APPTRACE_BUF_SIZE - 2) +#define RISCV_EBREAK 0x00100073 + +uint32_t stub_esp_clk_cpu_freq(void); + + +static inline uint8_t stub_get_insn_size(uint8_t *insn) +{ + /* we use 32bit `ebreak`, so there possible oprions: + - 16bit instruction will be overwritten plus 2 bytes followed that instruction + - 32bit instruction will be overwritten completely + - > 32bit instruction will be overwritten partially (the first 4 bytes) + */ + return 4; +} + +static inline uint32_t stub_get_break_insn(uint8_t insn_sz) +{ + return RISCV_EBREAK; +} + +void stub_stack_data_pool_init(uint8_t *data, size_t sz); + +#endif /*ESP32C3_FLASHER_STUB_H */ diff --git a/contrib/loaders/flash/esp/esp32c3/stub_flasher_code.inc b/contrib/loaders/flash/esp/esp32c3/stub_flasher_code.inc new file mode 100644 index 0000000000..175d93d15a --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_flasher_code.inc @@ -0,0 +1,602 @@ + 0xb7, 0x47, 0xc8, 0x3f, 0x83, 0xc7, 0x07, 0x39, 0x13, 0x05, 0x30, 0x10, + 0x8d, 0xcf, 0xb7, 0x47, 0xc8, 0x3f, 0x93, 0x87, 0x87, 0x27, 0x98, 0x43, + 0x13, 0x05, 0x60, 0x10, 0x0d, 0xc7, 0x18, 0x4b, 0x1d, 0xc3, 0x79, 0x71, + 0x01, 0x45, 0x2a, 0xc4, 0x2a, 0xcc, 0xc8, 0x43, 0x81, 0x45, 0x7d, 0x56, + 0xfd, 0x56, 0x06, 0xd6, 0x2e, 0xc6, 0x2e, 0xce, 0x32, 0xc8, 0x36, 0xca, + 0x2c, 0x00, 0x02, 0x97, 0xb2, 0x50, 0x45, 0x61, 0x82, 0x80, 0x82, 0x80, + 0x29, 0xc5, 0xb7, 0x47, 0xc8, 0x3f, 0x83, 0xc7, 0x07, 0x39, 0xaa, 0x85, + 0x13, 0x05, 0x30, 0x10, 0xa1, 0xc3, 0xb7, 0x47, 0xc8, 0x3f, 0x93, 0x87, + 0x87, 0x27, 0x98, 0x43, 0x13, 0x05, 0x60, 0x10, 0x05, 0xcb, 0x18, 0x47, + 0x15, 0xc7, 0xc8, 0x43, 0x79, 0x71, 0x01, 0x48, 0x81, 0x48, 0x7d, 0x56, + 0xfd, 0x56, 0x06, 0xd6, 0x32, 0xc8, 0x42, 0xc4, 0x46, 0xc6, 0x36, 0xca, + 0x42, 0xcc, 0x46, 0xce, 0x30, 0x00, 0x02, 0x97, 0xb2, 0x50, 0x45, 0x61, + 0x82, 0x80, 0x13, 0x05, 0x20, 0x10, 0x82, 0x80, 0x82, 0x80, 0x39, 0xc1, + 0xb7, 0x47, 0xc8, 0x3f, 0x83, 0xc7, 0x07, 0x39, 0xaa, 0x85, 0x01, 0x45, + 0x95, 0xcf, 0xb7, 0x47, 0xc8, 0x3f, 0x93, 0x87, 0x87, 0x27, 0x88, 0x43, + 0x05, 0xc9, 0x58, 0x41, 0x01, 0x45, 0x0d, 0xc7, 0xc8, 0x43, 0x79, 0x71, + 0x01, 0x48, 0x81, 0x48, 0x7d, 0x56, 0xfd, 0x56, 0x06, 0xd6, 0x32, 0xc8, + 0x42, 0xc4, 0x46, 0xc6, 0x36, 0xca, 0x42, 0xcc, 0x46, 0xce, 0x30, 0x00, + 0x02, 0x97, 0xb2, 0x50, 0x45, 0x61, 0x82, 0x80, 0x01, 0x45, 0x82, 0x80, + 0x82, 0x80, 0x31, 0xc5, 0xb7, 0x47, 0xc8, 0x3f, 0x83, 0xc7, 0x07, 0x39, + 0xaa, 0x85, 0x13, 0x05, 0x30, 0x10, 0xa9, 0xc3, 0xb7, 0x47, 0xc8, 0x3f, + 0x93, 0x87, 0x87, 0x27, 0x98, 0x43, 0x13, 0x05, 0x60, 0x10, 0x0d, 0xcb, + 0x14, 0x4f, 0x9d, 0xc6, 0x58, 0x4f, 0xc8, 0x43, 0x79, 0x71, 0x01, 0x48, + 0x81, 0x48, 0x7d, 0x56, 0xfd, 0x56, 0x06, 0xd6, 0x32, 0xc8, 0x42, 0xc4, + 0x46, 0xc6, 0x36, 0xca, 0x42, 0xcc, 0x46, 0xce, 0x30, 0x00, 0x02, 0x97, + 0xb2, 0x50, 0x45, 0x61, 0x82, 0x80, 0x13, 0x05, 0x20, 0x10, 0x82, 0x80, + 0x82, 0x80, 0x1c, 0x41, 0xb9, 0xc3, 0xb7, 0x47, 0xc8, 0x3f, 0x83, 0xc7, + 0x07, 0x39, 0xaa, 0x85, 0x01, 0x45, 0x95, 0xcf, 0xb7, 0x47, 0xc8, 0x3f, + 0x93, 0x87, 0x87, 0x27, 0x88, 0x43, 0x05, 0xc9, 0x18, 0x4d, 0x01, 0x45, + 0x0d, 0xc7, 0xc8, 0x43, 0x79, 0x71, 0x01, 0x48, 0x81, 0x48, 0x7d, 0x56, + 0xfd, 0x56, 0x06, 0xd6, 0x32, 0xc8, 0x42, 0xc4, 0x46, 0xc6, 0x36, 0xca, + 0x42, 0xcc, 0x46, 0xce, 0x30, 0x00, 0x02, 0x97, 0xb2, 0x50, 0x45, 0x61, + 0x82, 0x80, 0x01, 0x45, 0x82, 0x80, 0x82, 0x80, 0xb7, 0x47, 0xc8, 0x3f, + 0x83, 0xc7, 0x07, 0x39, 0x2e, 0x86, 0x91, 0xcf, 0xb7, 0x47, 0xc8, 0x3f, + 0x93, 0x87, 0x87, 0x27, 0x98, 0x43, 0x01, 0xcb, 0x03, 0x23, 0x47, 0x01, + 0x63, 0x05, 0x03, 0x00, 0xaa, 0x85, 0xc8, 0x43, 0x02, 0x83, 0x82, 0x80, + 0xb7, 0x27, 0x00, 0x60, 0x23, 0xac, 0x07, 0x04, 0x37, 0x07, 0x00, 0x10, + 0x98, 0xc3, 0x98, 0x43, 0x7d, 0xff, 0xa8, 0x4f, 0x41, 0x81, 0x13, 0x75, + 0xf5, 0x0f, 0x82, 0x80, 0xb7, 0x47, 0xc8, 0x3f, 0x03, 0xa5, 0x87, 0x28, + 0x59, 0x81, 0x05, 0x89, 0x82, 0x80, 0x01, 0x45, 0x82, 0x80, 0xb7, 0x47, + 0xc8, 0x3f, 0x23, 0xa6, 0x07, 0x28, 0x82, 0x80, 0xb7, 0x46, 0xc8, 0x3f, + 0x93, 0x86, 0x86, 0x27, 0x98, 0x4a, 0xb7, 0x07, 0x80, 0x00, 0x3e, 0x05, + 0xf9, 0x8f, 0x21, 0x67, 0x7d, 0x17, 0xf9, 0x8d, 0xcd, 0x8f, 0xb7, 0x85, + 0x3f, 0x00, 0x41, 0x11, 0x6d, 0x8d, 0x06, 0xc6, 0xc9, 0x8f, 0x9c, 0xca, + 0xf9, 0x37, 0xb2, 0x40, 0x01, 0x45, 0x41, 0x01, 0x82, 0x80, 0xb7, 0x47, + 0xc8, 0x3f, 0x37, 0x07, 0x38, 0x40, 0x93, 0x87, 0x87, 0x27, 0x13, 0x07, + 0x67, 0x1e, 0xd8, 0xcb, 0x98, 0x4b, 0x93, 0x17, 0x87, 0x00, 0x63, 0xd6, + 0x07, 0x02, 0x93, 0x57, 0xf7, 0x00, 0x93, 0x16, 0x17, 0x01, 0x93, 0xf7, + 0xf7, 0x07, 0x91, 0xe6, 0x13, 0x77, 0xf5, 0x07, 0x01, 0x45, 0x63, 0x0c, + 0xf7, 0x00, 0x41, 0x11, 0x06, 0xc6, 0x71, 0x37, 0xb2, 0x40, 0x13, 0x05, + 0x10, 0x10, 0x41, 0x01, 0x82, 0x80, 0x01, 0x45, 0x82, 0x80, 0x82, 0x80, + 0x83, 0x47, 0x05, 0x00, 0x85, 0x8b, 0x81, 0xcb, 0xb7, 0x47, 0xc8, 0x3f, + 0x03, 0xa5, 0x87, 0x28, 0x5d, 0x81, 0x05, 0x89, 0x82, 0x80, 0x01, 0x45, + 0x82, 0x80, 0x83, 0x47, 0x05, 0x00, 0x85, 0x8b, 0x99, 0xc3, 0x01, 0x45, + 0x82, 0x80, 0x13, 0x05, 0x30, 0x10, 0x82, 0x80, 0x83, 0x47, 0x05, 0x00, + 0x85, 0x8b, 0x81, 0xcb, 0x50, 0xd5, 0x10, 0xd5, 0x23, 0x28, 0x05, 0x02, + 0x4c, 0xd1, 0x23, 0x2a, 0x05, 0x02, 0x82, 0x80, 0x83, 0x47, 0x05, 0x00, + 0x85, 0x8b, 0x99, 0xc7, 0x83, 0xd7, 0xc5, 0xff, 0x01, 0x45, 0x23, 0x9f, + 0xf5, 0xfe, 0x82, 0x80, 0x13, 0x05, 0x30, 0x10, 0x82, 0x80, 0x03, 0x47, + 0x05, 0x00, 0x1d, 0xef, 0xb7, 0x47, 0xc8, 0x3f, 0x23, 0x26, 0x05, 0x02, + 0x83, 0xa6, 0xc7, 0x38, 0xb7, 0x47, 0xc8, 0x3f, 0x23, 0x24, 0x05, 0x02, + 0x83, 0xa7, 0x87, 0x38, 0x23, 0x28, 0x05, 0x02, 0x23, 0x2a, 0x05, 0x02, + 0x85, 0x83, 0x23, 0x26, 0x05, 0x00, 0x54, 0xc9, 0x23, 0x28, 0x05, 0x00, + 0xbe, 0x96, 0x23, 0x22, 0x05, 0x02, 0x1c, 0xcd, 0x54, 0xcd, 0x1c, 0xd1, + 0x23, 0x24, 0x05, 0x00, 0x13, 0x67, 0x17, 0x00, 0xb7, 0x47, 0xc8, 0x3f, + 0x23, 0x00, 0xe5, 0x00, 0x93, 0x87, 0x87, 0x27, 0x51, 0x05, 0x88, 0xcf, + 0x37, 0x47, 0xc8, 0x3f, 0xc1, 0x07, 0x23, 0x22, 0xf7, 0x38, 0x01, 0x45, + 0x82, 0x80, 0x79, 0x71, 0x22, 0xd4, 0x26, 0xd2, 0x06, 0xd6, 0x4a, 0xd0, + 0x4e, 0xce, 0x52, 0xcc, 0x56, 0xca, 0x5a, 0xc8, 0x2a, 0x84, 0xfd, 0x54, + 0x1c, 0x40, 0x03, 0x29, 0x44, 0x00, 0x48, 0x40, 0x9c, 0x43, 0x2e, 0xc6, + 0x82, 0x97, 0xaa, 0x89, 0xb2, 0x45, 0x63, 0x11, 0x05, 0x12, 0x93, 0x44, + 0xf9, 0xff, 0x85, 0x88, 0x93, 0x97, 0x24, 0x00, 0xa2, 0x97, 0x23, 0xa4, + 0x07, 0x00, 0x5c, 0x40, 0x26, 0x85, 0x89, 0x04, 0x85, 0x07, 0x5c, 0xc0, + 0x1c, 0x40, 0x8e, 0x04, 0xa2, 0x94, 0xdc, 0x43, 0x82, 0x97, 0x1c, 0x40, + 0x83, 0xaa, 0x04, 0x00, 0xdc, 0x47, 0x82, 0x97, 0x79, 0xc1, 0x03, 0xdb, + 0x0a, 0x00, 0x63, 0x00, 0x0b, 0x0c, 0x01, 0x4a, 0x58, 0x54, 0x1c, 0x58, + 0x63, 0xe6, 0xe7, 0x04, 0x5c, 0x50, 0x18, 0x58, 0x99, 0x8f, 0xc5, 0xc7, + 0x58, 0x54, 0x19, 0xe3, 0xfd, 0x17, 0xc5, 0xc3, 0xb3, 0x04, 0x4b, 0x41, + 0x63, 0xf3, 0x97, 0x00, 0xbe, 0x84, 0x08, 0x58, 0x18, 0x50, 0x54, 0x54, + 0x1c, 0x58, 0x3a, 0x95, 0x63, 0xe0, 0xd7, 0x06, 0x1c, 0x58, 0x54, 0x50, + 0xa6, 0x97, 0x63, 0xe1, 0xd7, 0x06, 0x5c, 0x54, 0x89, 0xcb, 0x1c, 0x58, + 0x54, 0x50, 0xa6, 0x97, 0x63, 0x9b, 0xd7, 0x00, 0x23, 0x28, 0x04, 0x02, + 0x31, 0xe9, 0x01, 0xa0, 0x5c, 0x54, 0x18, 0x58, 0xfd, 0x17, 0x99, 0x8f, + 0x7d, 0xbf, 0x5c, 0x54, 0xfd, 0x17, 0xe3, 0xe8, 0x97, 0xfe, 0x1c, 0x58, + 0x1c, 0xd4, 0x23, 0x28, 0x04, 0x02, 0x54, 0x54, 0x1c, 0x54, 0x63, 0x9a, + 0xf6, 0x00, 0x23, 0x26, 0x04, 0x02, 0x14, 0x54, 0x5c, 0x50, 0x63, 0xf4, + 0xf6, 0x00, 0x5c, 0x50, 0x1c, 0xd4, 0x1c, 0x58, 0x3a, 0x85, 0xa6, 0x97, + 0x1c, 0xd8, 0xc9, 0xb7, 0x5c, 0x54, 0x18, 0x58, 0xfd, 0x17, 0x99, 0x8f, + 0xe3, 0xed, 0x97, 0xfa, 0x1c, 0x58, 0xa6, 0x97, 0x1c, 0xd8, 0x7d, 0xb7, + 0x93, 0x05, 0x2a, 0x00, 0x26, 0x86, 0xd6, 0x95, 0x26, 0x9a, 0x97, 0x00, + 0xc8, 0xff, 0xe7, 0x80, 0x20, 0xf2, 0xe3, 0x67, 0x6a, 0xf5, 0x23, 0x90, + 0x0a, 0x00, 0x13, 0x79, 0x19, 0x00, 0x1c, 0x40, 0x0a, 0x09, 0x22, 0x99, + 0x48, 0x40, 0x9c, 0x47, 0x83, 0x25, 0x89, 0x00, 0x82, 0x97, 0xb2, 0x50, + 0x22, 0x54, 0x4e, 0x85, 0x92, 0x54, 0x02, 0x59, 0xf2, 0x49, 0x62, 0x4a, + 0xd2, 0x4a, 0x42, 0x4b, 0x45, 0x61, 0x82, 0x80, 0x90, 0x45, 0xd4, 0x45, + 0x63, 0x14, 0x96, 0x00, 0xe3, 0x82, 0x96, 0xec, 0x98, 0x41, 0xdc, 0x41, + 0x33, 0x07, 0xe0, 0x40, 0x33, 0x35, 0xe0, 0x00, 0xb3, 0x07, 0xf0, 0x40, + 0x89, 0x8f, 0x98, 0xc9, 0xdc, 0xc9, 0xe3, 0xc5, 0xd7, 0xea, 0x63, 0x94, + 0xf6, 0x00, 0xe3, 0x61, 0xc7, 0xea, 0x93, 0x09, 0x70, 0x10, 0x65, 0xbf, + 0x83, 0x47, 0x05, 0x00, 0x85, 0x8b, 0xb9, 0xc7, 0x1c, 0x45, 0x01, 0x11, + 0x22, 0xcc, 0x85, 0x8b, 0x8a, 0x07, 0xaa, 0x97, 0xdc, 0x47, 0x26, 0xca, + 0x4a, 0xc8, 0x4e, 0xc6, 0x06, 0xce, 0x32, 0x89, 0xae, 0x84, 0x2a, 0x84, + 0x93, 0x09, 0x45, 0x00, 0x63, 0xfe, 0xb7, 0x00, 0x01, 0x45, 0xf2, 0x40, + 0x62, 0x44, 0xd2, 0x44, 0x42, 0x49, 0xb2, 0x49, 0x05, 0x61, 0x82, 0x80, + 0xca, 0x85, 0x4e, 0x85, 0x89, 0x35, 0x75, 0xf5, 0x1c, 0x44, 0x85, 0x8b, + 0x8a, 0x07, 0xa2, 0x97, 0xdc, 0x47, 0xe3, 0xe7, 0xf4, 0xfe, 0xe9, 0xbf, + 0x13, 0x05, 0x30, 0x10, 0x82, 0x80, 0x83, 0x47, 0x05, 0x00, 0x85, 0x8b, + 0xa9, 0xc3, 0x1c, 0x45, 0x41, 0x11, 0x22, 0xc4, 0x85, 0x8b, 0x8a, 0x07, + 0xaa, 0x97, 0xdc, 0x47, 0x26, 0xc2, 0x4a, 0xc0, 0x06, 0xc6, 0xae, 0x84, + 0x2a, 0x84, 0x13, 0x09, 0x45, 0x00, 0x1c, 0x44, 0x85, 0x8b, 0x8a, 0x07, + 0xa2, 0x97, 0xdc, 0x47, 0x99, 0xe3, 0x01, 0x45, 0x29, 0xa0, 0xa6, 0x85, + 0x4a, 0x85, 0xc5, 0x3b, 0x6d, 0xd5, 0xb2, 0x40, 0x22, 0x44, 0x92, 0x44, + 0x02, 0x49, 0x41, 0x01, 0x82, 0x80, 0x13, 0x05, 0x30, 0x10, 0x82, 0x80, + 0x01, 0x11, 0x22, 0xcc, 0x26, 0xca, 0x4a, 0xc8, 0x4e, 0xc6, 0x52, 0xc4, + 0x06, 0xce, 0x83, 0x47, 0x05, 0x00, 0x2a, 0x84, 0x2e, 0x89, 0x85, 0x8b, + 0xb2, 0x84, 0x13, 0x0a, 0x45, 0x00, 0xfd, 0x59, 0xb9, 0xe7, 0x01, 0x45, + 0xf2, 0x40, 0x62, 0x44, 0xd2, 0x44, 0x42, 0x49, 0xb2, 0x49, 0x22, 0x4a, + 0x05, 0x61, 0x82, 0x80, 0x58, 0x54, 0x89, 0xa0, 0x18, 0x58, 0x54, 0x54, + 0x3e, 0x97, 0x63, 0xe0, 0xe6, 0x02, 0x18, 0x58, 0x54, 0x54, 0x3e, 0x97, + 0x63, 0x1e, 0xd7, 0x04, 0x58, 0x54, 0x1c, 0x54, 0x63, 0x74, 0xf7, 0x00, + 0x1c, 0x54, 0x5c, 0xd4, 0x23, 0x28, 0x04, 0x02, 0x61, 0xf5, 0x01, 0xa0, + 0x5c, 0x40, 0xdc, 0x47, 0x82, 0x97, 0x39, 0xc1, 0xa6, 0x85, 0x52, 0x85, + 0xbd, 0x33, 0x18, 0x58, 0x5c, 0x58, 0xe3, 0xe1, 0xe7, 0xfc, 0x58, 0x58, + 0x1c, 0x58, 0x1d, 0x8f, 0x75, 0xd3, 0x83, 0x27, 0x09, 0x00, 0x63, 0x73, + 0xf7, 0x00, 0xba, 0x87, 0x23, 0x20, 0xf9, 0x00, 0x18, 0x58, 0x48, 0x50, + 0x14, 0x58, 0x3a, 0x95, 0x58, 0x58, 0xe3, 0x61, 0xd7, 0xfa, 0x18, 0x58, + 0x54, 0x58, 0x3e, 0x97, 0xe3, 0xef, 0xe6, 0xfa, 0x18, 0x58, 0xba, 0x97, + 0x1c, 0xd8, 0x4d, 0xbf, 0x90, 0x44, 0xd4, 0x44, 0x63, 0x14, 0x36, 0x01, + 0xe3, 0x8d, 0x36, 0xfb, 0x98, 0x40, 0xdc, 0x40, 0x33, 0x07, 0xe0, 0x40, + 0xb3, 0x35, 0xe0, 0x00, 0xb3, 0x07, 0xf0, 0x40, 0x8d, 0x8f, 0x98, 0xc8, + 0xdc, 0xc8, 0xe3, 0xc0, 0xd7, 0xfa, 0xe3, 0x98, 0xf6, 0xf4, 0xe3, 0x6c, + 0xc7, 0xf8, 0xa1, 0xb7, 0x83, 0x47, 0x05, 0x00, 0x85, 0x8b, 0x99, 0xe3, + 0x01, 0x45, 0x82, 0x80, 0x1c, 0x45, 0x85, 0x8b, 0x89, 0x07, 0x8e, 0x07, + 0xaa, 0x97, 0x9c, 0x47, 0xf1, 0x17, 0xe3, 0xe7, 0xb7, 0xfe, 0x1c, 0x45, + 0x41, 0x11, 0x26, 0xc2, 0x85, 0x8b, 0x8a, 0x07, 0xaa, 0x97, 0xd8, 0x47, + 0x1c, 0x45, 0x93, 0x84, 0x45, 0x00, 0x22, 0xc4, 0x85, 0x8b, 0x89, 0x07, + 0x8e, 0x07, 0xaa, 0x97, 0x9c, 0x47, 0x4a, 0xc0, 0x06, 0xc6, 0x26, 0x97, + 0x2e, 0x89, 0x2a, 0x84, 0x63, 0xf1, 0xe7, 0x06, 0xb2, 0x85, 0x11, 0x05, + 0x7d, 0x31, 0x41, 0xe1, 0x1c, 0x44, 0x13, 0x97, 0x04, 0x01, 0x41, 0x83, + 0x85, 0x8b, 0x8a, 0x07, 0xa2, 0x97, 0xd4, 0x47, 0x1c, 0x44, 0x36, 0x97, + 0x85, 0x8b, 0x89, 0x07, 0x8e, 0x07, 0xa2, 0x97, 0x9c, 0x47, 0x63, 0xe0, + 0xe7, 0x06, 0x1c, 0x44, 0x18, 0x44, 0x85, 0x8b, 0x05, 0x8b, 0x89, 0x07, + 0x0a, 0x07, 0x8e, 0x07, 0x22, 0x97, 0xa2, 0x97, 0x58, 0x47, 0xc8, 0x43, + 0x3a, 0x95, 0x31, 0xc1, 0x1c, 0x44, 0x85, 0x8b, 0x8a, 0x07, 0x3e, 0x94, + 0x5c, 0x44, 0xbe, 0x94, 0x44, 0xc4, 0x23, 0x10, 0x25, 0x01, 0x23, 0x11, + 0x05, 0x00, 0x11, 0x05, 0x35, 0xa0, 0x1c, 0x45, 0x18, 0x45, 0x85, 0x8b, + 0x05, 0x8b, 0x89, 0x07, 0x0a, 0x07, 0x8e, 0x07, 0x2a, 0x97, 0xaa, 0x97, + 0x58, 0x47, 0xc8, 0x43, 0x1c, 0x44, 0x3a, 0x95, 0x85, 0x8b, 0x8a, 0x07, + 0x3e, 0x94, 0x5c, 0x44, 0xbe, 0x94, 0x44, 0xc4, 0x79, 0xf5, 0x01, 0x45, + 0xb2, 0x40, 0x22, 0x44, 0x92, 0x44, 0x02, 0x49, 0x41, 0x01, 0x82, 0x80, + 0xb7, 0x87, 0x00, 0x60, 0x03, 0xa6, 0x87, 0x0b, 0x13, 0x15, 0x06, 0x01, + 0x41, 0x81, 0x93, 0x57, 0x06, 0x01, 0x63, 0x17, 0xf5, 0x00, 0x93, 0x07, + 0xf6, 0xff, 0x75, 0x57, 0x63, 0x75, 0xf7, 0x02, 0xb7, 0x45, 0xc8, 0x3f, + 0x37, 0x45, 0xc8, 0x3f, 0x41, 0x11, 0x93, 0x85, 0x85, 0x0b, 0x13, 0x05, + 0x05, 0x0c, 0x06, 0xc6, 0x97, 0x00, 0xc8, 0xff, 0xe7, 0x80, 0x40, 0x90, + 0xb2, 0x40, 0x13, 0x05, 0x80, 0x02, 0x41, 0x01, 0x82, 0x80, 0x82, 0x80, + 0xb7, 0x06, 0x0c, 0x60, 0xbc, 0x4e, 0x1d, 0x71, 0x86, 0xce, 0xa9, 0x83, + 0xa2, 0xcc, 0xa6, 0xca, 0xca, 0xc8, 0xce, 0xc6, 0xd2, 0xc4, 0xd6, 0xc2, + 0xda, 0xc0, 0x5e, 0xde, 0x62, 0xdc, 0x66, 0xda, 0x6a, 0xd8, 0x6e, 0xd6, + 0x8d, 0x8b, 0x05, 0x47, 0x63, 0x89, 0xe7, 0x06, 0x9d, 0xcb, 0x09, 0x47, + 0x21, 0x49, 0x63, 0x83, 0xe7, 0x00, 0x01, 0x49, 0xfd, 0x57, 0x63, 0x0c, + 0xf5, 0x06, 0x63, 0x4c, 0xa0, 0x06, 0xf6, 0x40, 0x66, 0x44, 0x4a, 0x85, + 0xd6, 0x44, 0x46, 0x49, 0xb6, 0x49, 0x26, 0x4a, 0x96, 0x4a, 0x06, 0x4b, + 0xf2, 0x5b, 0x62, 0x5c, 0xd2, 0x5c, 0x42, 0x5d, 0xb2, 0x5d, 0x25, 0x61, + 0x82, 0x80, 0x03, 0xa9, 0x86, 0x05, 0x37, 0x87, 0x00, 0x60, 0x03, 0x27, + 0x87, 0x0b, 0x13, 0x79, 0xf9, 0x3f, 0x93, 0x07, 0x19, 0x00, 0x13, 0x19, + 0x07, 0x01, 0x13, 0x59, 0x09, 0x01, 0x93, 0x56, 0x07, 0x01, 0x63, 0x19, + 0xd9, 0x00, 0x7d, 0x17, 0xf5, 0x56, 0x63, 0xe5, 0xe6, 0x00, 0x33, 0x59, + 0xf9, 0x02, 0x5d, 0xb7, 0x13, 0x09, 0x80, 0x02, 0xdd, 0xbf, 0x98, 0x46, + 0x94, 0x46, 0x13, 0x09, 0x00, 0x05, 0x0d, 0x8b, 0x51, 0xdb, 0x01, 0x49, + 0xe3, 0x18, 0xf7, 0xf8, 0x13, 0x09, 0x00, 0x0a, 0x61, 0xb7, 0x13, 0x05, + 0x00, 0x0a, 0x37, 0x84, 0x00, 0x60, 0x3c, 0x58, 0x93, 0x74, 0xf5, 0x3f, + 0x93, 0x9c, 0x04, 0x01, 0x3e, 0xc4, 0x13, 0xdc, 0xe7, 0x01, 0x3c, 0x58, + 0x37, 0x07, 0xfc, 0xff, 0x93, 0xdc, 0x0c, 0x01, 0x3e, 0xc2, 0x93, 0xd9, + 0xd7, 0x01, 0xe2, 0x47, 0x13, 0x06, 0xf7, 0x0f, 0x93, 0xfb, 0xfc, 0x3f, + 0x93, 0x96, 0x8b, 0x00, 0xf1, 0x8f, 0xd5, 0x8f, 0x7d, 0x17, 0x93, 0xf9, + 0x19, 0x00, 0x93, 0x96, 0x29, 0x01, 0xf9, 0x8f, 0x37, 0x07, 0xe8, 0xff, + 0xd5, 0x8f, 0x7d, 0x17, 0x93, 0x16, 0x3c, 0x01, 0xf9, 0x8f, 0x37, 0x07, + 0x20, 0x00, 0xd5, 0x8f, 0x13, 0x07, 0x07, 0xf0, 0xf9, 0x8f, 0x93, 0xe7, + 0x87, 0x02, 0x3e, 0xcc, 0x83, 0x27, 0x04, 0x08, 0x37, 0x47, 0xc0, 0xff, + 0x7d, 0x17, 0xf9, 0x8f, 0x37, 0xc7, 0x3f, 0x00, 0xd9, 0x8f, 0x23, 0x20, + 0xf4, 0x08, 0x3c, 0x58, 0x37, 0x07, 0x02, 0xfe, 0x7d, 0x17, 0xf9, 0x8f, + 0x37, 0x07, 0xc8, 0x00, 0xd9, 0x8f, 0x3c, 0xd8, 0x7c, 0x58, 0x37, 0x07, + 0xc0, 0xff, 0x7d, 0x17, 0xf9, 0x8f, 0x7c, 0xd8, 0x7c, 0x58, 0x37, 0x07, + 0x80, 0x80, 0x7d, 0x17, 0xf9, 0x8f, 0x7c, 0xd8, 0x7c, 0x58, 0x37, 0x07, + 0x40, 0x00, 0xb7, 0x06, 0x04, 0x00, 0xd9, 0x8f, 0x7c, 0xd8, 0x3c, 0x58, + 0x65, 0x77, 0x7d, 0x17, 0xdd, 0x9b, 0x3c, 0xd8, 0x3c, 0x58, 0x93, 0x86, + 0x06, 0xf0, 0x01, 0x45, 0xf9, 0x8f, 0x3c, 0xd8, 0x3c, 0x58, 0x62, 0x8b, + 0x93, 0xe7, 0x87, 0x00, 0x3c, 0xd8, 0xb7, 0xe7, 0x00, 0x60, 0xf8, 0x43, + 0x55, 0x8f, 0xf8, 0xc3, 0xf8, 0x43, 0xb7, 0xc6, 0xfd, 0xff, 0xfd, 0x16, + 0x75, 0x8f, 0xf8, 0xc3, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x80, 0x79, + 0xb7, 0x07, 0x28, 0x00, 0x93, 0x87, 0x87, 0x02, 0x23, 0x2c, 0xf4, 0x0a, + 0xb7, 0x27, 0x25, 0x26, 0x93, 0x87, 0x57, 0x62, 0x23, 0x2e, 0xf4, 0x0a, + 0xb7, 0x06, 0x0c, 0x60, 0xbc, 0x4e, 0x05, 0x47, 0xa9, 0x83, 0x8d, 0x8b, + 0x63, 0x87, 0xe7, 0x06, 0x95, 0xc3, 0x09, 0x47, 0x21, 0x4d, 0x63, 0x87, + 0xe7, 0x02, 0xb7, 0x45, 0xc8, 0x3f, 0x37, 0x45, 0xc8, 0x3f, 0x93, 0x85, + 0x85, 0x0b, 0x13, 0x05, 0x45, 0x0f, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0xa0, 0x70, 0x01, 0xa0, 0x03, 0xad, 0x86, 0x05, 0xd1, 0x33, 0x13, 0x7d, + 0xfd, 0x3f, 0x05, 0x0d, 0x33, 0x5d, 0xa5, 0x03, 0x65, 0x3b, 0xaa, 0x8d, + 0x63, 0x61, 0x95, 0x06, 0x81, 0x46, 0xb3, 0x57, 0x95, 0x02, 0x13, 0xd7, + 0x17, 0x00, 0x2a, 0x97, 0x33, 0x57, 0xf7, 0x02, 0x63, 0x83, 0xe4, 0x06, + 0xb7, 0x45, 0xc8, 0x3f, 0x37, 0x45, 0xc8, 0x3f, 0x93, 0x85, 0x45, 0x12, + 0x13, 0x05, 0x45, 0x13, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x40, 0x6c, + 0x01, 0xa0, 0x98, 0x46, 0x94, 0x46, 0x0d, 0x8b, 0x15, 0xc3, 0x13, 0x0d, + 0x00, 0x0a, 0xe3, 0x0f, 0xf7, 0xfa, 0xb7, 0x45, 0xc8, 0x3f, 0x37, 0x45, + 0xc8, 0x3f, 0x93, 0x85, 0x85, 0x0b, 0x13, 0x05, 0x45, 0x0f, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0x69, 0x01, 0xa0, 0x13, 0x0d, 0x00, 0x05, + 0x71, 0xbf, 0x93, 0x07, 0x00, 0x05, 0x63, 0x86, 0xf4, 0x1e, 0x93, 0x07, + 0x00, 0x0a, 0xe3, 0x95, 0xf4, 0xfa, 0x8d, 0x47, 0x85, 0x46, 0x93, 0x0d, + 0x00, 0x1e, 0x37, 0x04, 0x0c, 0x60, 0x38, 0x4c, 0x29, 0x83, 0x0d, 0x8b, + 0x63, 0x99, 0x06, 0x1c, 0x34, 0x4c, 0x37, 0x45, 0x0f, 0x00, 0x13, 0x05, + 0x05, 0x24, 0x93, 0xf6, 0x06, 0xc0, 0x34, 0xcc, 0xb3, 0x84, 0xa4, 0x02, + 0x34, 0x4c, 0xfd, 0x17, 0x93, 0xf7, 0xf7, 0x3f, 0x93, 0xf6, 0x06, 0xc0, + 0xd5, 0x8f, 0x3c, 0xcc, 0x3c, 0x4c, 0xfd, 0x76, 0x93, 0x86, 0xf6, 0x3f, + 0xf5, 0x8f, 0xb1, 0x80, 0x3c, 0xcc, 0x93, 0x97, 0x04, 0x01, 0xc1, 0x83, + 0xc2, 0x04, 0xdd, 0x8c, 0xb7, 0x87, 0x00, 0x60, 0x23, 0xae, 0x97, 0x0a, + 0x85, 0x46, 0x63, 0x16, 0xd7, 0x00, 0x98, 0x43, 0x13, 0x67, 0x07, 0x54, + 0x98, 0xc3, 0x73, 0x25, 0x20, 0x7e, 0xb3, 0xb5, 0xac, 0x02, 0x6a, 0x86, + 0x81, 0x46, 0x33, 0x85, 0xac, 0x02, 0xef, 0x00, 0x30, 0x5c, 0x73, 0x10, + 0x25, 0x7e, 0xe2, 0x47, 0x37, 0x07, 0xfc, 0xff, 0x93, 0x06, 0xf7, 0x0f, + 0xa2, 0x0b, 0xf5, 0x8f, 0x7d, 0x17, 0xb3, 0xe7, 0x77, 0x01, 0xca, 0x09, + 0xf9, 0x8f, 0xb3, 0xe7, 0x37, 0x01, 0xb7, 0x09, 0xe8, 0xff, 0xfd, 0x19, + 0x4e, 0x0b, 0xb3, 0xf7, 0x37, 0x01, 0xb3, 0xe7, 0x67, 0x01, 0x37, 0x0b, + 0x20, 0x00, 0x13, 0x0b, 0x0b, 0xf0, 0xb3, 0xf7, 0x67, 0x01, 0x93, 0xe7, + 0x87, 0x02, 0xb7, 0x04, 0x18, 0x00, 0x3e, 0xcc, 0xfd, 0x8c, 0x37, 0x07, + 0x08, 0x00, 0x63, 0x96, 0xe4, 0x04, 0x37, 0x87, 0x00, 0x60, 0x34, 0x53, + 0x37, 0x06, 0xf2, 0xff, 0x7d, 0x16, 0xf1, 0x8e, 0x37, 0x06, 0x06, 0x00, + 0xd1, 0x8e, 0x34, 0xd3, 0x34, 0x53, 0x49, 0x76, 0x7d, 0x16, 0xf1, 0x8e, + 0x19, 0x66, 0xd1, 0x8e, 0x34, 0xd3, 0x34, 0x53, 0x79, 0x76, 0x13, 0x06, + 0xf6, 0x3f, 0xf1, 0x8e, 0x05, 0x66, 0x13, 0x06, 0x06, 0xc0, 0xd1, 0x8e, + 0x34, 0xd3, 0x34, 0x53, 0x41, 0x66, 0x93, 0xe6, 0x06, 0x20, 0x34, 0xd3, + 0x34, 0x53, 0xd1, 0x8e, 0x34, 0xd3, 0x13, 0x97, 0xd7, 0x00, 0x63, 0x5e, + 0x07, 0x02, 0x37, 0x84, 0x00, 0x60, 0x3c, 0x58, 0x71, 0x77, 0x13, 0x07, + 0xf7, 0x03, 0x93, 0xf7, 0xf7, 0xfb, 0x3c, 0xd8, 0x5c, 0x4c, 0x13, 0x05, + 0x20, 0x03, 0xf9, 0x8f, 0x93, 0xe7, 0x07, 0x14, 0x5c, 0xcc, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0xe0, 0x54, 0xb7, 0x07, 0x10, 0x00, 0x63, 0x94, + 0xf4, 0x24, 0x3c, 0x58, 0x93, 0xf7, 0xf7, 0xf7, 0x3c, 0xd8, 0x37, 0x84, + 0x00, 0x60, 0x3c, 0x58, 0x92, 0x46, 0x37, 0x07, 0x00, 0xe0, 0x7d, 0x17, + 0xf9, 0x8f, 0x37, 0x07, 0x00, 0x20, 0xb3, 0xfa, 0xe6, 0x00, 0xb3, 0xea, + 0x57, 0x01, 0x23, 0x28, 0x54, 0x07, 0x0d, 0x45, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0x51, 0x3c, 0x58, 0xa2, 0x46, 0x37, 0x07, 0x00, 0x40, + 0x7d, 0x17, 0xf9, 0x8f, 0x37, 0x07, 0x00, 0xc0, 0x33, 0xfa, 0xe6, 0x00, + 0x33, 0xea, 0x47, 0x01, 0x23, 0x28, 0x44, 0x07, 0x3c, 0x58, 0x85, 0x46, + 0x13, 0x07, 0x00, 0x10, 0x93, 0xf7, 0xf7, 0xef, 0x63, 0x03, 0xdc, 0x00, + 0x01, 0x47, 0xd9, 0x8f, 0x37, 0x87, 0x00, 0x60, 0x3c, 0xdb, 0x3c, 0x5b, + 0x37, 0x07, 0x00, 0xfc, 0x7d, 0x17, 0x89, 0x46, 0xf9, 0x8f, 0x37, 0x07, + 0x00, 0x04, 0x63, 0x03, 0xdc, 0x00, 0x01, 0x47, 0xd9, 0x8f, 0x37, 0x87, + 0x00, 0x60, 0x3c, 0xdb, 0x13, 0x05, 0xc0, 0x12, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0x4b, 0xfd, 0xb6, 0x99, 0x47, 0x05, 0xb5, 0x85, 0x47, + 0x63, 0x04, 0xf7, 0x10, 0x37, 0x87, 0x00, 0x60, 0x1c, 0x43, 0x93, 0xf7, + 0xf7, 0xab, 0x1c, 0xc3, 0xb1, 0x36, 0xb7, 0xe7, 0x00, 0x60, 0xb8, 0x43, + 0x6d, 0x9b, 0xb8, 0xc3, 0xb8, 0x43, 0x13, 0x67, 0x87, 0x00, 0xb8, 0xc3, + 0x93, 0x07, 0x00, 0x1e, 0x63, 0x9b, 0xfd, 0x10, 0x1c, 0x44, 0x93, 0xe7, + 0x47, 0x00, 0x1c, 0xc4, 0x93, 0x07, 0x00, 0x02, 0x63, 0x1e, 0xf5, 0x0e, + 0x01, 0x4a, 0x91, 0x47, 0xe9, 0x4d, 0x05, 0x44, 0x93, 0x06, 0xb0, 0x06, + 0x11, 0x46, 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, 0x3e, 0xc6, 0x97, 0x10, + 0xc8, 0xff, 0xe7, 0x80, 0xe0, 0xd5, 0xb2, 0x47, 0xa2, 0x8a, 0x93, 0x96, + 0x47, 0x00, 0xc1, 0x8e, 0x09, 0x46, 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, + 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, 0x40, 0xd4, 0xee, 0x86, 0x0d, 0x46, + 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, + 0x20, 0xd3, 0xd6, 0x87, 0x01, 0x47, 0x89, 0x46, 0x15, 0x46, 0x81, 0x45, + 0x13, 0x05, 0x60, 0x06, 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, 0x00, 0xd2, + 0xd6, 0x87, 0x11, 0x47, 0x99, 0x46, 0x15, 0x46, 0x81, 0x45, 0x13, 0x05, + 0x60, 0x06, 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, 0xa0, 0xd0, 0x93, 0x66, + 0x0a, 0x09, 0x19, 0x46, 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, 0x97, 0x10, + 0xc8, 0xff, 0xe7, 0x80, 0x20, 0xcf, 0x89, 0x47, 0x01, 0x47, 0x85, 0x46, + 0x25, 0x46, 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, 0x97, 0x10, 0xc8, 0xff, + 0xe7, 0x80, 0x00, 0xce, 0x89, 0x47, 0x11, 0x47, 0x95, 0x46, 0x19, 0x46, + 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, + 0xa0, 0xcc, 0x85, 0x47, 0x19, 0x47, 0x9d, 0x46, 0x19, 0x46, 0x81, 0x45, + 0x13, 0x05, 0x60, 0x06, 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, 0x40, 0xcb, + 0x93, 0x07, 0x00, 0x05, 0x63, 0x83, 0xf4, 0x06, 0x93, 0x07, 0x00, 0x0a, + 0x85, 0x46, 0x63, 0x8f, 0xf4, 0x04, 0xb7, 0x45, 0xc8, 0x3f, 0x37, 0x45, + 0xc8, 0x3f, 0x93, 0x85, 0x85, 0x0b, 0x13, 0x05, 0xc5, 0x15, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0x36, 0x01, 0xa0, 0x0d, 0x4a, 0x95, 0x47, + 0xa1, 0x4d, 0x01, 0x44, 0x21, 0xb7, 0x1c, 0x44, 0xed, 0x9b, 0x1c, 0xc4, + 0x93, 0x07, 0x00, 0x02, 0x63, 0x12, 0xf5, 0x02, 0x99, 0x4d, 0x05, 0x44, + 0x93, 0x06, 0x90, 0x06, 0x11, 0x46, 0x81, 0x45, 0x13, 0x05, 0x60, 0x06, + 0x97, 0x10, 0xc8, 0xff, 0xe7, 0x80, 0x40, 0xc5, 0x0d, 0x4a, 0x95, 0x47, + 0x81, 0x4a, 0xd5, 0xbd, 0x91, 0x4d, 0x01, 0x44, 0xc5, 0xb7, 0x81, 0x46, + 0xb7, 0x07, 0x0c, 0x60, 0x98, 0x47, 0x71, 0x9b, 0x55, 0x8f, 0x98, 0xc7, + 0xb8, 0x4f, 0xfd, 0x76, 0x93, 0x86, 0xf6, 0x3f, 0x13, 0x77, 0x07, 0xc0, + 0xb8, 0xcf, 0xb8, 0x4f, 0x75, 0x8f, 0x13, 0x67, 0x07, 0x40, 0xb8, 0xcf, + 0xb7, 0x57, 0x4b, 0x4c, 0x37, 0x87, 0x00, 0x60, 0x93, 0x87, 0xb7, 0xc4, + 0x23, 0x2e, 0xf7, 0x0a, 0xe9, 0xb9, 0x3c, 0x58, 0x93, 0xe7, 0x07, 0x08, + 0x75, 0xbb, 0x5d, 0x71, 0x4e, 0xde, 0x61, 0x46, 0xae, 0x89, 0x2c, 0x00, + 0xa6, 0xc2, 0x86, 0xc6, 0xa2, 0xc4, 0xca, 0xc0, 0x52, 0xdc, 0x56, 0xda, + 0x5a, 0xd8, 0x5e, 0xd6, 0x62, 0xd4, 0xaa, 0x84, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0x3b, 0x31, 0xed, 0x03, 0x47, 0x81, 0x00, 0x93, 0x07, + 0x90, 0x0e, 0x7d, 0x55, 0x63, 0x14, 0xf7, 0x02, 0xe1, 0x04, 0x01, 0x49, + 0x01, 0x44, 0xb7, 0x0a, 0x00, 0xbe, 0x37, 0x0a, 0x80, 0x00, 0x05, 0x4b, + 0xb1, 0x4b, 0x37, 0x0c, 0x00, 0xc4, 0x83, 0x47, 0x91, 0x00, 0x63, 0x41, + 0xf9, 0x02, 0x23, 0xa0, 0x89, 0x00, 0x01, 0x45, 0xb6, 0x40, 0x26, 0x44, + 0x96, 0x44, 0x06, 0x49, 0xf2, 0x59, 0x62, 0x5a, 0xd2, 0x5a, 0x42, 0x5b, + 0xb2, 0x5b, 0x22, 0x5c, 0x61, 0x61, 0x82, 0x80, 0x21, 0x46, 0x8a, 0x85, + 0x26, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0x35, 0x19, 0xc1, + 0x7d, 0x55, 0xd9, 0xbf, 0x02, 0x47, 0xb3, 0x07, 0x57, 0x01, 0x63, 0xe6, + 0x47, 0x01, 0xb3, 0x07, 0x87, 0x01, 0x63, 0xf0, 0x47, 0x03, 0xe3, 0x6e, + 0x8b, 0xfa, 0xb3, 0x07, 0x74, 0x03, 0x05, 0x04, 0x93, 0x86, 0x84, 0x00, + 0x42, 0x04, 0x41, 0x80, 0xce, 0x97, 0x98, 0xc7, 0x12, 0x47, 0xd4, 0xc3, + 0xd8, 0xc7, 0x92, 0x47, 0x05, 0x09, 0xa1, 0x07, 0xbe, 0x94, 0x41, 0xbf, + 0x13, 0x01, 0x01, 0xde, 0x23, 0x2a, 0x91, 0x20, 0x93, 0x04, 0x15, 0x00, + 0x23, 0x2c, 0x81, 0x20, 0x23, 0x26, 0x31, 0x21, 0x23, 0x24, 0x41, 0x21, + 0x23, 0x22, 0x51, 0x21, 0x23, 0x20, 0x61, 0x21, 0x23, 0x2e, 0x11, 0x20, + 0x23, 0x28, 0x21, 0x21, 0x32, 0x8a, 0x33, 0x04, 0xa6, 0x00, 0xb2, 0x04, + 0xb3, 0x09, 0xb5, 0x00, 0x93, 0x0a, 0x00, 0x20, 0x13, 0x0b, 0xf0, 0x0f, + 0xb3, 0x07, 0x44, 0x41, 0x63, 0xe6, 0x37, 0x03, 0x01, 0x45, 0x83, 0x20, + 0xc1, 0x21, 0x03, 0x24, 0x81, 0x21, 0x83, 0x24, 0x41, 0x21, 0x03, 0x29, + 0x01, 0x21, 0x83, 0x29, 0xc1, 0x20, 0x03, 0x2a, 0x81, 0x20, 0x83, 0x2a, + 0x41, 0x20, 0x03, 0x2b, 0x01, 0x20, 0x13, 0x01, 0x01, 0x22, 0x82, 0x80, + 0x85, 0x47, 0x7d, 0x79, 0x23, 0x00, 0xf4, 0x00, 0x26, 0x99, 0x63, 0x04, + 0x99, 0x02, 0x13, 0x06, 0x00, 0x20, 0x8a, 0x85, 0x4a, 0x85, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0x20, 0x29, 0x1d, 0xe5, 0x81, 0x47, 0x33, 0x07, + 0xf1, 0x00, 0x03, 0x47, 0x07, 0x00, 0x63, 0x08, 0x67, 0x01, 0x23, 0x00, + 0x04, 0x00, 0x85, 0x67, 0x05, 0x04, 0xbe, 0x94, 0x61, 0xbf, 0x85, 0x07, + 0xe3, 0x93, 0x57, 0xff, 0x83, 0x47, 0x04, 0x00, 0x13, 0x09, 0x09, 0x20, + 0xe9, 0xf3, 0xe5, 0xb7, 0x7d, 0x55, 0x71, 0xb7, 0x01, 0x11, 0x4a, 0xc8, + 0x2e, 0x89, 0x85, 0x65, 0xfd, 0x15, 0x22, 0xcc, 0x06, 0xce, 0x26, 0xca, + 0x4e, 0xc6, 0x52, 0xc4, 0xb3, 0x77, 0xb5, 0x00, 0x2a, 0x84, 0x81, 0xc7, + 0xfd, 0x77, 0x33, 0x74, 0xf5, 0x00, 0xb3, 0x77, 0xb9, 0x00, 0x89, 0xc7, + 0x2e, 0x99, 0xfd, 0x75, 0x33, 0x79, 0xb9, 0x00, 0xb7, 0x04, 0xce, 0x3f, + 0x03, 0xa7, 0x04, 0xff, 0xb3, 0x07, 0x24, 0x01, 0x54, 0x43, 0x63, 0xfb, + 0xf6, 0x00, 0x7d, 0x55, 0xf2, 0x40, 0x62, 0x44, 0xd2, 0x44, 0x42, 0x49, + 0xb2, 0x49, 0x22, 0x4a, 0x05, 0x61, 0x82, 0x80, 0x5c, 0x47, 0xb3, 0x77, + 0xf4, 0x02, 0xe5, 0xf7, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xc0, 0x20, + 0x79, 0xfd, 0x83, 0xa7, 0x04, 0xff, 0xcc, 0x47, 0x83, 0xa9, 0x87, 0x00, + 0xb3, 0x57, 0xb9, 0x02, 0x33, 0x79, 0xb9, 0x02, 0xb3, 0x54, 0xb4, 0x02, + 0x13, 0x84, 0x17, 0x00, 0xb3, 0xd9, 0xb9, 0x02, 0x63, 0x13, 0x09, 0x00, + 0x3e, 0x84, 0x33, 0xfa, 0x34, 0x03, 0x33, 0x8a, 0x49, 0x41, 0x63, 0x53, + 0x44, 0x01, 0x22, 0x8a, 0x33, 0x09, 0x9a, 0x00, 0x63, 0x9d, 0x24, 0x01, + 0x33, 0x04, 0x44, 0x41, 0x63, 0xe1, 0x89, 0x02, 0x22, 0x99, 0x33, 0x05, + 0x89, 0x40, 0x63, 0x47, 0x80, 0x02, 0x01, 0x45, 0x41, 0xbf, 0x26, 0x85, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x80, 0x19, 0x49, 0xf1, 0x85, 0x04, + 0xe1, 0xbf, 0x33, 0x55, 0x39, 0x03, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0x20, 0x18, 0x25, 0xf9, 0x4e, 0x99, 0x33, 0x04, 0x34, 0x41, 0xe9, 0xb7, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x40, 0x17, 0x39, 0xfd, 0x7d, 0x14, + 0xc9, 0xb7, 0x41, 0x11, 0x37, 0x45, 0xc8, 0x3f, 0x26, 0xc2, 0x41, 0x46, + 0x93, 0x04, 0x85, 0x27, 0x81, 0x45, 0x13, 0x05, 0x85, 0x27, 0x06, 0xc6, + 0x22, 0xc4, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0x37, 0xb7, 0x47, + 0xc8, 0x3f, 0x93, 0x87, 0x07, 0x00, 0x13, 0x85, 0x47, 0x02, 0x9c, 0xc0, + 0x9c, 0x43, 0x37, 0x47, 0xc8, 0x3f, 0x85, 0x46, 0xc8, 0xc0, 0x23, 0x08, + 0xd7, 0x38, 0x82, 0x97, 0x1d, 0xe5, 0x9c, 0x44, 0x2a, 0x84, 0x85, 0xe3, + 0xb7, 0x47, 0xc8, 0x3f, 0x03, 0xa7, 0x47, 0x38, 0xb7, 0x06, 0x80, 0x00, + 0x1c, 0x43, 0xd5, 0x8f, 0x1c, 0xc3, 0x22, 0x85, 0xb2, 0x40, 0x22, 0x44, + 0x92, 0x44, 0x41, 0x01, 0x82, 0x80, 0x9c, 0x43, 0xc8, 0x44, 0x82, 0x97, + 0x71, 0xdd, 0x7d, 0x54, 0xed, 0xb7, 0x39, 0x71, 0x61, 0x73, 0xa1, 0x66, + 0x26, 0xda, 0x56, 0xd2, 0x5e, 0xce, 0x06, 0xde, 0x22, 0xdc, 0x4a, 0xd8, + 0x4e, 0xd6, 0x52, 0xd4, 0x5a, 0xd0, 0x62, 0xcc, 0xc1, 0x06, 0x1a, 0x91, + 0x8a, 0x96, 0xe1, 0x77, 0xb6, 0x97, 0x37, 0x47, 0xc8, 0x3f, 0x23, 0x26, + 0xf7, 0x38, 0xb7, 0x47, 0xc8, 0x3f, 0x21, 0x67, 0xaa, 0x8a, 0xae, 0x8b, + 0x23, 0xa4, 0xe7, 0x38, 0x99, 0x3f, 0xaa, 0x84, 0x01, 0xe9, 0x11, 0x6a, + 0x79, 0x1a, 0x01, 0x49, 0x13, 0x7c, 0xca, 0xff, 0x63, 0x61, 0x79, 0x03, + 0x21, 0x63, 0x1a, 0x91, 0xf2, 0x50, 0x26, 0x85, 0x62, 0x54, 0xd2, 0x54, + 0x42, 0x59, 0xb2, 0x59, 0x22, 0x5a, 0x92, 0x5a, 0x02, 0x5b, 0xf2, 0x4b, + 0x62, 0x4c, 0x21, 0x61, 0x82, 0x80, 0x33, 0x84, 0x2b, 0x41, 0xa2, 0x89, + 0x63, 0x7a, 0x8a, 0x00, 0x62, 0x84, 0x22, 0x85, 0xef, 0xe0, 0xff, 0xfe, + 0x2a, 0x8b, 0x31, 0xed, 0xfd, 0x54, 0xe9, 0xb7, 0x93, 0x77, 0x34, 0x00, + 0xfd, 0xd7, 0x71, 0x98, 0x6d, 0xf4, 0x8d, 0x47, 0xe3, 0xe8, 0x37, 0xff, + 0xa1, 0x67, 0x61, 0x74, 0xc1, 0x07, 0x71, 0x14, 0x8a, 0x97, 0x3e, 0x94, + 0x11, 0x46, 0xa2, 0x85, 0x33, 0x05, 0x59, 0x01, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0x05, 0x61, 0xf9, 0x4e, 0x85, 0xef, 0xe0, 0x3f, 0xfb, + 0xaa, 0x84, 0x79, 0xd1, 0x4e, 0x86, 0xa2, 0x85, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0x26, 0x26, 0x85, 0xef, 0xe0, 0xbf, 0xf4, 0x4d, 0xf9, + 0xef, 0xe0, 0xdf, 0xef, 0xaa, 0x84, 0x3d, 0xd9, 0x65, 0xb7, 0xaa, 0x85, + 0x22, 0x86, 0x33, 0x05, 0x59, 0x01, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0xa0, 0x01, 0xaa, 0x89, 0x5a, 0x85, 0xef, 0xe0, 0x7f, 0xf2, 0x33, 0xe5, + 0xa9, 0x00, 0x49, 0xf5, 0x22, 0x99, 0xef, 0xe0, 0x3f, 0xed, 0x29, 0xd5, + 0x41, 0xb7, 0x17, 0xf3, 0xc7, 0xff, 0x67, 0x00, 0x63, 0xff, 0x35, 0x73, + 0x5d, 0x71, 0x13, 0x03, 0x03, 0x50, 0xca, 0xc0, 0x4e, 0xde, 0x52, 0xdc, + 0x86, 0xc6, 0xa2, 0xc4, 0xa6, 0xc2, 0x56, 0xda, 0x5a, 0xd8, 0x5e, 0xd6, + 0x62, 0xd4, 0x66, 0xd2, 0x6a, 0xd0, 0x6e, 0xce, 0x4d, 0x69, 0x1a, 0x91, + 0x10, 0x08, 0x93, 0x06, 0x09, 0xb0, 0xb2, 0x96, 0xe1, 0x77, 0xb6, 0x97, + 0x37, 0x47, 0xc8, 0x3f, 0x23, 0x26, 0xf7, 0x38, 0xb7, 0x47, 0xc8, 0x3f, + 0x21, 0x67, 0x2a, 0x8a, 0x23, 0xa4, 0xe7, 0x38, 0x3d, 0x3d, 0xaa, 0x89, + 0x63, 0x1b, 0x05, 0x16, 0x83, 0x25, 0xca, 0x00, 0x03, 0x25, 0x8a, 0x00, + 0x37, 0x44, 0xc8, 0x3f, 0xb5, 0x74, 0xef, 0xe0, 0xff, 0xfe, 0x03, 0x27, + 0x0a, 0x00, 0x93, 0x07, 0x84, 0x27, 0x10, 0x08, 0xd8, 0xcf, 0x03, 0x27, + 0x0a, 0x01, 0x93, 0x06, 0x09, 0xb0, 0xb2, 0x96, 0x98, 0xd3, 0x03, 0x27, + 0x4a, 0x00, 0xb5, 0x7b, 0x13, 0x8c, 0xcb, 0x50, 0xd8, 0xd3, 0x13, 0x87, + 0x04, 0x51, 0x36, 0x97, 0x93, 0x06, 0x09, 0xb0, 0xb2, 0x96, 0x98, 0xd7, + 0x41, 0x77, 0x36, 0x97, 0xd8, 0xd7, 0x98, 0xdb, 0x93, 0x8c, 0x8b, 0x50, + 0xb3, 0x87, 0x86, 0x01, 0xb6, 0x94, 0x3e, 0xc2, 0xb3, 0x87, 0x96, 0x01, + 0x23, 0xa8, 0x04, 0x50, 0x81, 0x4a, 0x13, 0x04, 0x84, 0x27, 0x3e, 0xc4, + 0x83, 0x27, 0x4a, 0x00, 0x63, 0xf3, 0xfa, 0x10, 0xb3, 0x87, 0x57, 0x41, + 0x23, 0xa2, 0xf4, 0x50, 0xcd, 0x67, 0x18, 0x08, 0x93, 0x87, 0x07, 0xb0, + 0xba, 0x97, 0x13, 0x85, 0x4b, 0x50, 0x3e, 0x95, 0xef, 0xe0, 0x7f, 0xf2, + 0x2a, 0x8d, 0x6d, 0xc1, 0x83, 0xac, 0x44, 0x50, 0xaa, 0x8d, 0x05, 0x4c, + 0x21, 0x6b, 0x63, 0x86, 0x0c, 0x00, 0x18, 0x50, 0x19, 0xc3, 0x63, 0x40, + 0x80, 0x03, 0x63, 0x45, 0x0c, 0x08, 0x18, 0x50, 0x63, 0x10, 0x0c, 0x0c, + 0x41, 0xe3, 0x6a, 0x85, 0xef, 0xe0, 0x7f, 0xea, 0x45, 0xed, 0x83, 0xa7, + 0x44, 0x50, 0xbe, 0x9a, 0x65, 0xb7, 0x54, 0x54, 0x18, 0x58, 0x03, 0x28, + 0x44, 0x02, 0xb3, 0x87, 0x66, 0x01, 0x99, 0x8f, 0x23, 0xa6, 0xf4, 0x50, + 0x22, 0x46, 0x92, 0x47, 0x08, 0x54, 0x33, 0xb8, 0x0c, 0x01, 0xee, 0x85, + 0x06, 0x08, 0x23, 0xa4, 0x94, 0x51, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0x20, 0xe8, 0x03, 0xa7, 0x84, 0x50, 0x54, 0x50, 0x03, 0x29, 0x04, 0x03, + 0xb3, 0x8c, 0xec, 0x40, 0x99, 0x8e, 0xba, 0x9d, 0x03, 0xa7, 0xc4, 0x50, + 0x54, 0xd0, 0x2a, 0x8c, 0x3a, 0x99, 0x58, 0x54, 0x23, 0x28, 0x24, 0x03, + 0x33, 0x09, 0xe9, 0x40, 0x63, 0x54, 0xa0, 0x00, 0xe3, 0x11, 0x69, 0xf9, + 0x14, 0x50, 0x4a, 0x85, 0x63, 0xf3, 0x26, 0x01, 0x36, 0x85, 0x05, 0xc9, + 0x63, 0x72, 0x65, 0x03, 0x63, 0x74, 0xd9, 0x00, 0xf5, 0x59, 0x81, 0xa0, + 0x33, 0x06, 0xab, 0x40, 0x93, 0x05, 0xf0, 0x0f, 0x3a, 0x95, 0x3a, 0xc6, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x80, 0x08, 0x32, 0x47, 0x21, 0x65, + 0x2a, 0x86, 0x48, 0x4c, 0xba, 0x85, 0xa1, 0x3d, 0x71, 0xfd, 0x58, 0x4c, + 0x4a, 0x97, 0x58, 0xcc, 0x18, 0x50, 0x33, 0x09, 0x27, 0x41, 0x58, 0x54, + 0x23, 0x20, 0x24, 0x03, 0x18, 0xd8, 0x05, 0xbf, 0x39, 0xf3, 0xc9, 0xb7, + 0xfd, 0x59, 0x4d, 0x63, 0x13, 0x03, 0x03, 0xb0, 0x1a, 0x91, 0xb6, 0x40, + 0x4e, 0x85, 0x26, 0x44, 0x96, 0x44, 0x06, 0x49, 0xf2, 0x59, 0x62, 0x5a, + 0xd2, 0x5a, 0x42, 0x5b, 0xb2, 0x5b, 0x22, 0x5c, 0x92, 0x5c, 0x02, 0x5d, + 0xf2, 0x4d, 0x61, 0x61, 0x82, 0x80, 0x5d, 0x71, 0xa6, 0xc2, 0x41, 0x73, + 0xc1, 0x64, 0x52, 0xdc, 0x5a, 0xd8, 0x86, 0xc6, 0xa2, 0xc4, 0xca, 0xc0, + 0x4e, 0xde, 0x56, 0xda, 0x5e, 0xd6, 0x62, 0xd4, 0x66, 0xd2, 0x6a, 0xd0, + 0x6e, 0xce, 0x93, 0x86, 0x04, 0x01, 0x1a, 0x91, 0x8a, 0x96, 0xe1, 0x77, + 0xb6, 0x97, 0x37, 0x47, 0xc8, 0x3f, 0x23, 0x26, 0xf7, 0x38, 0xb7, 0x47, + 0xc8, 0x3f, 0x21, 0x67, 0x2a, 0x8a, 0x23, 0xa4, 0xe7, 0x38, 0xb1, 0x39, + 0x2a, 0x8b, 0x63, 0x1e, 0x05, 0x0e, 0x83, 0x25, 0xca, 0x00, 0x03, 0x25, + 0x8a, 0x00, 0x37, 0x44, 0xc8, 0x3f, 0xc1, 0x79, 0xef, 0xe0, 0xdf, 0xe0, + 0x03, 0x27, 0x0a, 0x00, 0x93, 0x07, 0x84, 0x27, 0x93, 0x86, 0x04, 0x01, + 0xd8, 0xcf, 0x03, 0x27, 0x0a, 0x01, 0x8a, 0x96, 0x33, 0x89, 0x36, 0x01, + 0xf1, 0x19, 0x98, 0xd3, 0x23, 0xa6, 0x27, 0x03, 0x23, 0xa8, 0x27, 0x03, + 0x81, 0x4b, 0x13, 0x04, 0x84, 0x27, 0xb6, 0x99, 0xa1, 0x6a, 0x83, 0x27, + 0x4a, 0x00, 0x63, 0xfa, 0xfb, 0x0a, 0xb3, 0x87, 0x77, 0x41, 0x4e, 0x85, + 0x23, 0x2e, 0xf9, 0xfe, 0xef, 0xe0, 0xbf, 0xd7, 0x2a, 0x8c, 0x59, 0xcd, + 0x83, 0x2d, 0xc9, 0xff, 0xaa, 0x8c, 0x63, 0x84, 0x0d, 0x00, 0x1c, 0x50, + 0x99, 0xe3, 0x81, 0x44, 0xad, 0xa8, 0x08, 0x58, 0x44, 0x54, 0x6e, 0x8d, + 0xb3, 0x04, 0x95, 0x40, 0xb3, 0x87, 0xb4, 0x01, 0x63, 0xf4, 0xfa, 0x00, + 0x33, 0x8d, 0x9a, 0x40, 0x6a, 0x86, 0xe6, 0x85, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0xf6, 0x1c, 0x58, 0xea, 0x94, 0xb3, 0x8d, 0xad, 0x41, + 0xea, 0x9c, 0x3e, 0x9d, 0x1c, 0x50, 0x23, 0x28, 0xa4, 0x03, 0x63, 0x83, + 0xf4, 0x02, 0xe3, 0x9e, 0x54, 0xfb, 0x21, 0x66, 0x4c, 0x54, 0x48, 0x4c, + 0x29, 0x3b, 0x0d, 0xe9, 0x5c, 0x4c, 0xa6, 0x97, 0x5c, 0xcc, 0x1c, 0x50, + 0xb3, 0x84, 0x97, 0x40, 0x5c, 0x54, 0x04, 0xd0, 0x1c, 0xd8, 0x71, 0xbf, + 0x26, 0x86, 0xe3, 0xf1, 0x54, 0xff, 0x48, 0x54, 0x33, 0x86, 0x9a, 0x40, + 0x93, 0x05, 0xf0, 0x0f, 0x26, 0x95, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0xe0, 0xf0, 0xe1, 0xb7, 0xfd, 0x54, 0x62, 0x85, 0xef, 0xe0, 0x3f, 0xc9, + 0x11, 0xe5, 0x85, 0xe8, 0x83, 0x27, 0xc9, 0xff, 0xbe, 0x9b, 0xb1, 0xb7, + 0x7d, 0x5b, 0x41, 0x63, 0x1a, 0x91, 0xb6, 0x40, 0x5a, 0x85, 0x26, 0x44, + 0x96, 0x44, 0x06, 0x49, 0xf2, 0x59, 0x62, 0x5a, 0xd2, 0x5a, 0x42, 0x5b, + 0xb2, 0x5b, 0x22, 0x5c, 0x92, 0x5c, 0x02, 0x5d, 0xf2, 0x4d, 0x61, 0x61, + 0x82, 0x80, 0x75, 0x5b, 0xe9, 0xbf, 0x61, 0x73, 0x39, 0x71, 0x41, 0x03, + 0x06, 0xde, 0x26, 0xda, 0x4a, 0xd8, 0x4e, 0xd6, 0x52, 0xd4, 0x56, 0xd2, + 0x5a, 0xd0, 0x5e, 0xce, 0x22, 0xdc, 0x1a, 0x91, 0xaa, 0x8b, 0x2e, 0x89, + 0x32, 0x8a, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x60, 0x19, 0x37, 0x45, + 0xc8, 0x3f, 0x89, 0x45, 0x13, 0x05, 0xc5, 0x2a, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x00, 0x19, 0xa1, 0x67, 0xb7, 0x44, 0xc8, 0x3f, 0xa1, 0x6a, + 0x8a, 0x97, 0x81, 0x49, 0x93, 0x84, 0xc4, 0x2a, 0x33, 0x8b, 0x57, 0x41, + 0x63, 0x1a, 0x09, 0x02, 0x63, 0x14, 0x0a, 0x06, 0x93, 0x05, 0x80, 0x0d, + 0x26, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x20, 0xe9, 0x01, 0x45, + 0x21, 0x63, 0x41, 0x13, 0x1a, 0x91, 0xf2, 0x50, 0x62, 0x54, 0xd2, 0x54, + 0x42, 0x59, 0xb2, 0x59, 0x22, 0x5a, 0x92, 0x5a, 0x02, 0x5b, 0xf2, 0x4b, + 0x21, 0x61, 0x82, 0x80, 0x4a, 0x84, 0x63, 0xf3, 0x2a, 0x01, 0x21, 0x64, + 0x22, 0x86, 0xda, 0x85, 0x33, 0x85, 0x79, 0x01, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x00, 0xc1, 0x1d, 0xe9, 0x93, 0x77, 0x34, 0x00, 0x89, 0xeb, + 0x81, 0x46, 0x22, 0x86, 0xda, 0x85, 0x26, 0x85, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x40, 0x12, 0x33, 0x09, 0x89, 0x40, 0xa2, 0x99, 0x59, 0xbf, + 0xd2, 0x85, 0x26, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x40, 0x11, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x40, 0x0f, 0x59, 0xbf, 0x7d, 0x55, + 0x51, 0xbf, 0x19, 0x71, 0xba, 0xd8, 0xbe, 0xda, 0x37, 0x47, 0xc8, 0x3f, + 0xb7, 0x47, 0xc8, 0x3f, 0xd6, 0xc2, 0x86, 0xce, 0xa2, 0xcc, 0xa6, 0xca, + 0xca, 0xc8, 0xce, 0xc6, 0xd2, 0xc4, 0xda, 0xc0, 0x5e, 0xde, 0xaa, 0x8a, + 0xae, 0xd2, 0xb2, 0xd4, 0xb6, 0xd6, 0xc2, 0xdc, 0xc6, 0xde, 0x93, 0x87, + 0x87, 0x27, 0x13, 0x07, 0x47, 0x38, 0x63, 0xef, 0xe7, 0x08, 0x7d, 0x55, + 0xef, 0xf0, 0x4f, 0x9b, 0xdc, 0x10, 0x3e, 0xc6, 0x2d, 0x47, 0x79, 0x54, + 0x63, 0x4a, 0x57, 0x07, 0x96, 0x54, 0x26, 0x59, 0x36, 0x5a, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0x16, 0xb7, 0x47, 0x00, 0x60, 0x2a, 0x84, + 0x88, 0x5f, 0x09, 0xe4, 0x71, 0x89, 0x61, 0x15, 0x13, 0x34, 0x15, 0x00, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x80, 0xf5, 0x81, 0x45, 0xaa, 0x89, + 0x22, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0xb8, 0xef, 0xe0, + 0xff, 0xbc, 0x39, 0x15, 0x99, 0x47, 0x63, 0xec, 0xa7, 0x00, 0x37, 0x4b, + 0xc8, 0x3f, 0x93, 0x07, 0xcb, 0x09, 0x0a, 0x05, 0x3e, 0x95, 0x0c, 0x41, + 0x13, 0x0b, 0xcb, 0x09, 0x95, 0xed, 0x13, 0x84, 0xca, 0xff, 0x33, 0x34, + 0x80, 0x00, 0x33, 0x04, 0x80, 0x40, 0x13, 0x95, 0x09, 0x01, 0x41, 0x81, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x40, 0xf1, 0x22, 0x85, 0xf6, 0x40, + 0x66, 0x44, 0xd6, 0x44, 0x46, 0x49, 0xb6, 0x49, 0x26, 0x4a, 0x96, 0x4a, + 0x06, 0x4b, 0xf2, 0x5b, 0x09, 0x61, 0x82, 0x80, 0x23, 0xa0, 0x07, 0x00, + 0x91, 0x07, 0xb1, 0xbf, 0x91, 0x47, 0x2e, 0x84, 0xe3, 0x87, 0xfa, 0xfc, + 0xb7, 0x07, 0xce, 0x3f, 0x03, 0xa5, 0x07, 0xff, 0xc1, 0x67, 0xfd, 0x17, + 0x08, 0x41, 0x13, 0x07, 0x00, 0x10, 0x85, 0x66, 0x41, 0x66, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0xa0, 0xad, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0xe0, 0xad, 0xaa, 0x8b, 0x19, 0xc1, 0x7d, 0x54, 0x79, 0xbf, 0xad, 0x47, + 0x63, 0xe3, 0x57, 0x19, 0x13, 0x94, 0x2a, 0x00, 0xb7, 0x4a, 0xc8, 0x3f, + 0x93, 0x8a, 0xca, 0x06, 0x56, 0x94, 0x1c, 0x40, 0x82, 0x87, 0xca, 0x85, + 0x26, 0x85, 0x55, 0x32, 0x2a, 0x84, 0xb5, 0xbf, 0xca, 0x85, 0x26, 0x85, + 0xef, 0xf0, 0x1f, 0x84, 0xd5, 0xbf, 0x52, 0x86, 0xca, 0x85, 0x26, 0x85, + 0xef, 0xf0, 0x8f, 0xf7, 0xe5, 0xb7, 0x26, 0x85, 0xad, 0x39, 0xcd, 0xb7, + 0x26, 0x85, 0x71, 0x34, 0xf1, 0xbf, 0x52, 0x86, 0xca, 0x85, 0x26, 0x85, + 0xc9, 0x3b, 0xc9, 0xbf, 0xef, 0xe0, 0x1f, 0xaf, 0x39, 0x15, 0x99, 0x47, + 0x63, 0xe6, 0xa7, 0x00, 0x0a, 0x05, 0x5a, 0x95, 0x83, 0x2b, 0x05, 0x00, + 0x23, 0x20, 0x09, 0x00, 0xfd, 0x57, 0x21, 0x64, 0x63, 0x90, 0xf4, 0x04, + 0x95, 0x64, 0x93, 0x84, 0xa4, 0x0a, 0x13, 0x06, 0x00, 0x02, 0x0c, 0x08, + 0x22, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x20, 0xa4, 0x25, 0xfd, + 0x83, 0x57, 0x01, 0x01, 0x63, 0x95, 0x97, 0x02, 0x52, 0x45, 0xe3, 0xe6, + 0xab, 0xf6, 0xe2, 0x47, 0xaa, 0x97, 0xe3, 0xe2, 0xfb, 0xf6, 0x83, 0x47, + 0x21, 0x01, 0x13, 0x04, 0x04, 0x02, 0xe1, 0xfb, 0xca, 0x85, 0x19, 0xa0, + 0xca, 0x85, 0x26, 0x85, 0xef, 0xf0, 0xef, 0xe3, 0xb5, 0xb7, 0x69, 0x54, + 0xdd, 0xb5, 0xfd, 0x7a, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xc0, 0xda, + 0xb3, 0xfa, 0x54, 0x01, 0x09, 0x66, 0xd2, 0x85, 0x56, 0x85, 0x97, 0xf0, + 0xc7, 0xff, 0xe7, 0x80, 0x20, 0x9f, 0x19, 0xc1, 0x01, 0x44, 0xd1, 0xb5, + 0x05, 0x64, 0x7d, 0x14, 0x65, 0x8c, 0x52, 0x94, 0xa2, 0x85, 0x11, 0x46, + 0x4a, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xe0, 0xbf, 0x91, 0x45, + 0x26, 0x85, 0xef, 0xf0, 0x2f, 0xf7, 0x79, 0xfd, 0x93, 0x07, 0x30, 0x07, + 0x23, 0x00, 0xf4, 0x00, 0xa3, 0x00, 0x04, 0x00, 0x09, 0x66, 0xd2, 0x85, + 0x56, 0x85, 0x65, 0x3a, 0x61, 0xf5, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, + 0x60, 0xd5, 0x11, 0x44, 0x49, 0xb5, 0xfd, 0x7a, 0x97, 0xf0, 0xc7, 0xff, + 0xe7, 0x80, 0x80, 0xd4, 0xb3, 0xfa, 0x54, 0x01, 0x09, 0x66, 0xd2, 0x85, + 0x56, 0x85, 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0xe0, 0x98, 0xe3, 0x12, + 0x05, 0xec, 0x91, 0x45, 0x26, 0x85, 0xef, 0xf0, 0x6f, 0xf2, 0x2a, 0x84, + 0xe3, 0x1b, 0x05, 0xea, 0x85, 0x67, 0xfd, 0x17, 0xfd, 0x8c, 0x83, 0x47, + 0x09, 0x00, 0xd2, 0x94, 0x09, 0x66, 0x23, 0x80, 0xf4, 0x00, 0x83, 0x47, + 0x19, 0x00, 0xd2, 0x85, 0x56, 0x85, 0xa3, 0x80, 0xf4, 0x00, 0x83, 0x47, + 0x39, 0x00, 0xa3, 0x81, 0xf4, 0x00, 0x91, 0x3a, 0xe3, 0x15, 0x05, 0xe8, + 0x97, 0xf0, 0xc7, 0xff, 0xe7, 0x80, 0x00, 0xcf, 0x39, 0xbd, 0x26, 0x85, + 0xef, 0xe0, 0xdf, 0xf5, 0x61, 0xbd, 0x79, 0x54, 0x09, 0xbd, 0x00, 0x00, + 0x93, 0x87, 0x05, 0x00, 0x13, 0x08, 0x06, 0x00, 0x93, 0x88, 0x06, 0x00, + 0x13, 0x03, 0x05, 0x00, 0x63, 0x96, 0x06, 0x28, 0x37, 0x47, 0xc8, 0x3f, + 0x13, 0x07, 0x87, 0x17, 0x63, 0xf6, 0xc5, 0x0e, 0xb7, 0x06, 0x01, 0x00, + 0x63, 0x78, 0xd6, 0x0c, 0x93, 0x06, 0xf0, 0x0f, 0xb3, 0xb6, 0xc6, 0x00, + 0x93, 0x96, 0x36, 0x00, 0xb3, 0x58, 0xd6, 0x00, 0x33, 0x07, 0x17, 0x01, + 0x03, 0x47, 0x07, 0x00, 0xb3, 0x06, 0xd7, 0x00, 0x13, 0x07, 0x00, 0x02, + 0x33, 0x07, 0xd7, 0x40, 0x63, 0x0c, 0x07, 0x00, 0xb3, 0x97, 0xe7, 0x00, + 0xb3, 0x56, 0xd5, 0x00, 0x33, 0x18, 0xe6, 0x00, 0xb3, 0xe5, 0xf6, 0x00, + 0x33, 0x13, 0xe5, 0x00, 0x13, 0x55, 0x08, 0x01, 0x33, 0xf7, 0xa5, 0x02, + 0x13, 0x16, 0x08, 0x01, 0x13, 0x56, 0x06, 0x01, 0x93, 0x56, 0x03, 0x01, + 0xb3, 0xd5, 0xa5, 0x02, 0x13, 0x17, 0x07, 0x01, 0xb3, 0x66, 0xd7, 0x00, + 0xb3, 0x07, 0xb6, 0x02, 0x13, 0x87, 0x05, 0x00, 0x63, 0xfe, 0xf6, 0x00, + 0xb3, 0x86, 0x06, 0x01, 0x13, 0x87, 0xf5, 0xff, 0x63, 0xe8, 0x06, 0x01, + 0x63, 0xf6, 0xf6, 0x00, 0x13, 0x87, 0xe5, 0xff, 0xb3, 0x86, 0x06, 0x01, + 0xb3, 0x86, 0xf6, 0x40, 0xb3, 0xf7, 0xa6, 0x02, 0x13, 0x13, 0x03, 0x01, + 0x13, 0x53, 0x03, 0x01, 0xb3, 0xd6, 0xa6, 0x02, 0x93, 0x97, 0x07, 0x01, + 0x33, 0xe3, 0x67, 0x00, 0xb3, 0x05, 0xd6, 0x02, 0x13, 0x85, 0x06, 0x00, + 0x63, 0x7c, 0xb3, 0x00, 0x33, 0x03, 0x68, 0x00, 0x13, 0x85, 0xf6, 0xff, + 0x63, 0x66, 0x03, 0x01, 0x63, 0x74, 0xb3, 0x00, 0x13, 0x85, 0xe6, 0xff, + 0x13, 0x17, 0x07, 0x01, 0x33, 0x67, 0xa7, 0x00, 0x93, 0x05, 0x00, 0x00, + 0x6f, 0x00, 0x40, 0x0e, 0xb7, 0x08, 0x00, 0x01, 0x93, 0x06, 0x00, 0x01, + 0xe3, 0x6c, 0x16, 0xf3, 0x93, 0x06, 0x80, 0x01, 0x6f, 0xf0, 0x1f, 0xf3, + 0x63, 0x16, 0x06, 0x00, 0x93, 0x06, 0x10, 0x00, 0x33, 0xd8, 0xc6, 0x02, + 0xb7, 0x06, 0x01, 0x00, 0x63, 0x72, 0xd8, 0x0c, 0x93, 0x06, 0xf0, 0x0f, + 0x63, 0xf4, 0x06, 0x01, 0x93, 0x08, 0x80, 0x00, 0xb3, 0x56, 0x18, 0x01, + 0x33, 0x07, 0xd7, 0x00, 0x83, 0x46, 0x07, 0x00, 0x13, 0x07, 0x00, 0x02, + 0xb3, 0x86, 0x16, 0x01, 0x33, 0x07, 0xd7, 0x40, 0x63, 0x18, 0x07, 0x0a, + 0xb3, 0x87, 0x07, 0x41, 0x93, 0x05, 0x10, 0x00, 0x13, 0x56, 0x08, 0x01, + 0x93, 0x18, 0x08, 0x01, 0x93, 0xd8, 0x08, 0x01, 0x93, 0x56, 0x03, 0x01, + 0x33, 0xf7, 0xc7, 0x02, 0xb3, 0xd7, 0xc7, 0x02, 0x13, 0x17, 0x07, 0x01, + 0xb3, 0x66, 0xd7, 0x00, 0x33, 0x85, 0xf8, 0x02, 0x13, 0x87, 0x07, 0x00, + 0x63, 0xfe, 0xa6, 0x00, 0xb3, 0x86, 0x06, 0x01, 0x13, 0x87, 0xf7, 0xff, + 0x63, 0xe8, 0x06, 0x01, 0x63, 0xf6, 0xa6, 0x00, 0x13, 0x87, 0xe7, 0xff, + 0xb3, 0x86, 0x06, 0x01, 0xb3, 0x86, 0xa6, 0x40, 0xb3, 0xf7, 0xc6, 0x02, + 0x13, 0x13, 0x03, 0x01, 0x13, 0x53, 0x03, 0x01, 0xb3, 0xd6, 0xc6, 0x02, + 0x93, 0x97, 0x07, 0x01, 0x33, 0xe3, 0x67, 0x00, 0xb3, 0x88, 0xd8, 0x02, + 0x13, 0x85, 0x06, 0x00, 0x63, 0x7c, 0x13, 0x01, 0x33, 0x03, 0x68, 0x00, + 0x13, 0x85, 0xf6, 0xff, 0x63, 0x66, 0x03, 0x01, 0x63, 0x74, 0x13, 0x01, + 0x13, 0x85, 0xe6, 0xff, 0x13, 0x17, 0x07, 0x01, 0x33, 0x67, 0xa7, 0x00, + 0x13, 0x05, 0x07, 0x00, 0x67, 0x80, 0x00, 0x00, 0xb7, 0x06, 0x00, 0x01, + 0x93, 0x08, 0x00, 0x01, 0xe3, 0x62, 0xd8, 0xf4, 0x93, 0x08, 0x80, 0x01, + 0x6f, 0xf0, 0xdf, 0xf3, 0x33, 0x18, 0xe8, 0x00, 0xb3, 0xd5, 0xd7, 0x00, + 0x33, 0x13, 0xe5, 0x00, 0xb3, 0x56, 0xd5, 0x00, 0x13, 0x55, 0x08, 0x01, + 0xb3, 0x97, 0xe7, 0x00, 0x33, 0xf7, 0xa5, 0x02, 0xb3, 0xe8, 0xf6, 0x00, + 0x93, 0x17, 0x08, 0x01, 0x93, 0xd7, 0x07, 0x01, 0x13, 0xd6, 0x08, 0x01, + 0xb3, 0xd5, 0xa5, 0x02, 0x13, 0x17, 0x07, 0x01, 0x33, 0x67, 0xc7, 0x00, + 0xb3, 0x86, 0xb7, 0x02, 0x13, 0x86, 0x05, 0x00, 0x63, 0x7e, 0xd7, 0x00, + 0x33, 0x07, 0x07, 0x01, 0x13, 0x86, 0xf5, 0xff, 0x63, 0x68, 0x07, 0x01, + 0x63, 0x76, 0xd7, 0x00, 0x13, 0x86, 0xe5, 0xff, 0x33, 0x07, 0x07, 0x01, + 0xb3, 0x06, 0xd7, 0x40, 0x33, 0xf7, 0xa6, 0x02, 0x93, 0x98, 0x08, 0x01, + 0x93, 0xd8, 0x08, 0x01, 0xb3, 0xd6, 0xa6, 0x02, 0x13, 0x17, 0x07, 0x01, + 0xb3, 0x85, 0xd7, 0x02, 0xb3, 0x67, 0x17, 0x01, 0x13, 0x87, 0x06, 0x00, + 0x63, 0xfe, 0xb7, 0x00, 0xb3, 0x87, 0x07, 0x01, 0x13, 0x87, 0xf6, 0xff, + 0x63, 0xe8, 0x07, 0x01, 0x63, 0xf6, 0xb7, 0x00, 0x13, 0x87, 0xe6, 0xff, + 0xb3, 0x87, 0x07, 0x01, 0xb3, 0x87, 0xb7, 0x40, 0x93, 0x15, 0x06, 0x01, + 0xb3, 0xe5, 0xe5, 0x00, 0x6f, 0xf0, 0x5f, 0xeb, 0x63, 0xe6, 0xd5, 0x18, + 0x37, 0x07, 0x01, 0x00, 0x63, 0xf4, 0xe6, 0x04, 0x13, 0x08, 0xf0, 0x0f, + 0x33, 0x37, 0xd8, 0x00, 0x13, 0x17, 0x37, 0x00, 0x37, 0x48, 0xc8, 0x3f, + 0x13, 0x08, 0x88, 0x17, 0xb3, 0xd5, 0xe6, 0x00, 0xb3, 0x85, 0x05, 0x01, + 0x03, 0xc8, 0x05, 0x00, 0x93, 0x05, 0x00, 0x02, 0x33, 0x08, 0xe8, 0x00, + 0xb3, 0x85, 0x05, 0x41, 0x63, 0x96, 0x05, 0x02, 0x13, 0x07, 0x10, 0x00, + 0xe3, 0xec, 0xf6, 0xee, 0x33, 0x35, 0xc5, 0x00, 0x13, 0x47, 0x15, 0x00, + 0x6f, 0xf0, 0xdf, 0xee, 0xb7, 0x05, 0x00, 0x01, 0x13, 0x07, 0x00, 0x01, + 0xe3, 0xe0, 0xb6, 0xfc, 0x13, 0x07, 0x80, 0x01, 0x6f, 0xf0, 0x9f, 0xfb, + 0x33, 0x57, 0x06, 0x01, 0xb3, 0x96, 0xb6, 0x00, 0xb3, 0x66, 0xd7, 0x00, + 0x93, 0xde, 0x06, 0x01, 0x33, 0xd7, 0x07, 0x01, 0xb3, 0x78, 0xd7, 0x03, + 0xb3, 0x97, 0xb7, 0x00, 0x33, 0x58, 0x05, 0x01, 0x33, 0x63, 0xf8, 0x00, + 0x93, 0x97, 0x06, 0x01, 0x93, 0xd7, 0x07, 0x01, 0x13, 0x58, 0x03, 0x01, + 0x33, 0x16, 0xb6, 0x00, 0x33, 0x57, 0xd7, 0x03, 0x93, 0x98, 0x08, 0x01, + 0x33, 0xe8, 0x08, 0x01, 0x33, 0x8f, 0xe7, 0x02, 0x13, 0x0e, 0x07, 0x00, + 0x63, 0x7e, 0xe8, 0x01, 0x33, 0x08, 0xd8, 0x00, 0x13, 0x0e, 0xf7, 0xff, + 0x63, 0x68, 0xd8, 0x00, 0x63, 0x76, 0xe8, 0x01, 0x13, 0x0e, 0xe7, 0xff, + 0x33, 0x08, 0xd8, 0x00, 0x33, 0x08, 0xe8, 0x41, 0xb3, 0x78, 0xd8, 0x03, + 0x33, 0x58, 0xd8, 0x03, 0x93, 0x98, 0x08, 0x01, 0xb3, 0x8e, 0x07, 0x03, + 0x93, 0x17, 0x03, 0x01, 0x93, 0xd7, 0x07, 0x01, 0xb3, 0xe7, 0xf8, 0x00, + 0x13, 0x07, 0x08, 0x00, 0x63, 0xfe, 0xd7, 0x01, 0xb3, 0x87, 0xd7, 0x00, + 0x13, 0x07, 0xf8, 0xff, 0x63, 0xe8, 0xd7, 0x00, 0x63, 0xf6, 0xd7, 0x01, + 0x13, 0x07, 0xe8, 0xff, 0xb3, 0x87, 0xd7, 0x00, 0x13, 0x1e, 0x0e, 0x01, + 0xb3, 0x87, 0xd7, 0x41, 0xb7, 0x0e, 0x01, 0x00, 0x33, 0x67, 0xee, 0x00, + 0x13, 0x88, 0xfe, 0xff, 0x33, 0x73, 0x07, 0x01, 0x93, 0x58, 0x07, 0x01, + 0x33, 0x78, 0x06, 0x01, 0x13, 0x56, 0x06, 0x01, 0x33, 0x0e, 0x03, 0x03, + 0x33, 0x88, 0x08, 0x03, 0x93, 0x56, 0x0e, 0x01, 0x33, 0x03, 0xc3, 0x02, + 0x33, 0x03, 0x03, 0x01, 0xb3, 0x86, 0x66, 0x00, 0xb3, 0x88, 0xc8, 0x02, + 0x63, 0xf4, 0x06, 0x01, 0xb3, 0x88, 0xd8, 0x01, 0x13, 0xd6, 0x06, 0x01, + 0xb3, 0x08, 0x16, 0x01, 0x63, 0xe6, 0x17, 0x03, 0xe3, 0x9a, 0x17, 0xcf, + 0xb7, 0x07, 0x01, 0x00, 0x93, 0x87, 0xf7, 0xff, 0xb3, 0xf6, 0xf6, 0x00, + 0x93, 0x96, 0x06, 0x01, 0x33, 0x7e, 0xfe, 0x00, 0x33, 0x15, 0xb5, 0x00, + 0xb3, 0x86, 0xc6, 0x01, 0x93, 0x05, 0x00, 0x00, 0xe3, 0x7c, 0xd5, 0xda, + 0x13, 0x07, 0xf7, 0xff, 0x6f, 0xf0, 0x9f, 0xcc, 0x93, 0x05, 0x00, 0x00, + 0x13, 0x07, 0x00, 0x00, 0x6f, 0xf0, 0x5f, 0xda diff --git a/contrib/loaders/flash/esp/esp32c3/stub_flasher_data.inc b/contrib/loaders/flash/esp/esp32c3/stub_flasher_data.inc new file mode 100644 index 0000000000..5986f895fc --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_flasher_data.inc @@ -0,0 +1,53 @@ + 0xc2, 0x02, 0x38, 0x40, 0x28, 0x06, 0x38, 0x40, 0xa8, 0x02, 0x38, 0x40, + 0xa4, 0x04, 0x38, 0x40, 0xfe, 0x04, 0x38, 0x40, 0x90, 0x02, 0x38, 0x40, + 0x4c, 0x05, 0x38, 0x40, 0x7e, 0x02, 0x38, 0x40, 0x64, 0x02, 0x38, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0x40, 0xc8, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x38, 0x40, + 0xda, 0x01, 0x38, 0x40, 0xe8, 0x01, 0x38, 0x40, 0xcc, 0x01, 0x38, 0x40, + 0x8a, 0x16, 0x38, 0x40, 0xaa, 0x16, 0x38, 0x40, 0x94, 0x16, 0x38, 0x40, + 0x9e, 0x16, 0x38, 0x40, 0xfa, 0x17, 0x38, 0x40, 0xc0, 0x16, 0x38, 0x40, + 0x2a, 0x17, 0x38, 0x40, 0x8e, 0x17, 0x38, 0x40, 0xfa, 0x17, 0x38, 0x40, + 0xb0, 0x16, 0x38, 0x40, 0xb6, 0x16, 0x38, 0x40, 0xf2, 0x17, 0x38, 0x40, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x72, 0x74, 0x63, 0x5f, 0x63, 0x6c, 0x6b, 0x00, + 0x25, 0x73, 0x28, 0x77, 0x61, 0x72, 0x6e, 0x29, 0x3a, 0x20, 0x69, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x52, 0x54, 0x43, 0x5f, 0x58, 0x54, + 0x41, 0x4c, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x5f, 0x52, 0x45, 0x47, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x30, 0x78, 0x25, 0x30, 0x38, + 0x78, 0x00, 0x00, 0x00, 0x25, 0x73, 0x28, 0x65, 0x72, 0x72, 0x29, 0x3a, + 0x20, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x20, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x72, 0x74, 0x63, 0x5f, 0x63, 0x6c, 0x6b, 0x5f, + 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00, 0x25, 0x73, 0x28, 0x65, + 0x72, 0x72, 0x29, 0x3a, 0x20, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x20, 0x43, 0x50, 0x55, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x73, 0x28, 0x65, 0x72, 0x72, 0x29, 0x3a, 0x20, 0x69, 0x6e, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 diff --git a/contrib/loaders/flash/esp/esp32c3/stub_flasher_image.h b/contrib/loaders/flash/esp/esp32c3/stub_flasher_image.h new file mode 100644 index 0000000000..0cf964bae2 --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_flasher_image.h @@ -0,0 +1,8 @@ +#define ESP32C3_STUB_BSS_SIZE 0x000010cUL + +#define ESP32C3_STUB_ENTRY_ADDR 0x040381562UL + +#define ESP32C3_STUB_APPTRACE_CTRL_ADDR 0x03fc84288UL + +/*#define ESP32C3_STUB_BUILD_IDF_REV 055f31ef1da +*/ diff --git a/contrib/loaders/flash/esp/esp32c3/stub_rom_chip.h b/contrib/loaders/flash/esp/esp32c3/stub_rom_chip.h new file mode 100644 index 0000000000..fa1bf11d2b --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_rom_chip.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * ESP32-S2 specific rom header files * + * Copyright (C) 2019 Espressif Systems Ltd. * + * Author: Erhan Kurubas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ +#ifndef ESP_STUB_ROM_H +#define ESP_STUB_ROM_H + +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/miniz.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/cache.h" +#include "esp32c3/rom/efuse.h" +#include "esp32c3/rom/uart.h" +#include "esp32c3/rom/rtc.h" +#include "esp32c3/rom/sha.h" + +#endif diff --git a/contrib/loaders/flash/esp/esp32c3/stub_sha.c b/contrib/loaders/flash/esp/esp32c3/stub_sha.c new file mode 100644 index 0000000000..01a25c3234 --- /dev/null +++ b/contrib/loaders/flash/esp/esp32c3/stub_sha.c @@ -0,0 +1,44 @@ +/* Copyright 2021 Espressif Systems (Shanghai) PTE LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include +#include "stub_rom_chip.h" + +static SHA_CTX ctx; + +/* this function has the same implementation for ESP32-S2 + * TODO: move to common file */ +void stub_sha256_start(void) +{ + /* Enable SHA hardware */ + ets_sha_enable(); + ets_sha_init(&ctx, SHA2_256); +} + +void stub_sha256_data(const void *data, size_t data_len) +{ + if (data_len % 4 != 0) + return; + ets_sha_update(&ctx, data, data_len, false); +} + +void stub_sha256_finish(uint8_t *digest) +{ + if (digest == NULL) { + bzero(&ctx, sizeof(ctx)); + return; + } + ets_sha_finish(&ctx, digest); + ets_sha_disable(); +} diff --git a/contrib/loaders/flash/esp/stub_common.mk b/contrib/loaders/flash/esp/stub_common.mk index 3829e1c30a..620d712adb 100644 --- a/contrib/loaders/flash/esp/stub_common.mk +++ b/contrib/loaders/flash/esp/stub_common.mk @@ -32,7 +32,7 @@ SRCS += $(STUB_COMMON_PATH)/stub_flasher.c \ $(STUB_CHIP_PATH)/stub_sha.c \ $(IDF_PATH)/components/app_trace/app_trace.c \ $(IDF_PATH)/components/app_trace/app_trace_util.c \ - $(IDF_PATH)/components/xtensa/eri.c + $(IDF_PATH)/components/app_trace/app_trace_membufs_proto.c BUILD_DIR = build @@ -50,18 +50,19 @@ $(BUILD_DIR): $(Q) mkdir $@ CFLAGS += -std=gnu99 -Wall -Werror -Os \ - -mtext-section-literals -mlongcalls -nostdlib -fno-builtin -flto \ + -nostdlib -fno-builtin -flto \ -Wl,-static -g -ffunction-sections -Wl,--gc-sections INCLUDES += -I. -I$(STUB_COMMON_PATH) -I$(STUB_CHIP_PATH) -I$(IDF_PATH)/components/soc/include \ - -I$(IDF_PATH)/components/app_trace/include -I$(IDF_PATH)/components/xtensa/include -I$(IDF_PATH)/components/driver/include \ + -I$(IDF_PATH)/components/app_trace/include -I$(IDF_PATH)/components/driver/include \ -I$(IDF_PATH)/components/freertos/include -I$(IDF_PATH)/components/log/include -I$(IDF_PATH)/components/heap/include \ -I$(IDF_PATH)/components/bootloader_support/include -I$(IDF_PATH)/components/esp_rom/include \ -I$(IDF_PATH)/components/esp_common/include -I$(IDF_PATH)/components/efuse/include \ - -I$(IDF_PATH)/components/esp_hw_support/include -I$(IDF_PATH)/components/freertos/port/xtensa/include \ + -I$(IDF_PATH)/components/esp_hw_support/include \ -I$(IDF_PATH)/components/hal/include -I$(IDF_PATH)/components/esp_timer/include \ -I$(IDF_PATH)/components/esp_system/include -I$(IDF_PATH)/components/newlib/platform_include \ - -I$(IDF_PATH)/components/spi_flash/private_include + -I$(IDF_PATH)/components/spi_flash/private_include -I$(IDF_PATH)/components/app_trace/private_include \ + -I$(IDF_PATH)/components/app_trace/port/include DEFINES += -Dasm=__asm__ @@ -71,7 +72,7 @@ LDFLAGS += -L$(STUB_COMMON_PATH) -T$(STUB_LD_SCRIPT) -Wl,--start-group -lgcc -lc $(STUB_ELF): $(SRCS) $(STUB_COMMON_PATH)/stub_common.ld $(STUB_LD_SCRIPT) $(BUILD_DIR) @echo " CC $^ -> $@" - $(Q) $(CROSS)gcc $(CFLAGS) -DSTUB_IMAGE=1 -Wl,-Map=$(@:.elf=.map) -o $@ $(LDFLAGS) $(filter %.c, $^) + $(Q) $(CROSS)gcc $(CFLAGS) -DSTUB_IMAGE=1 -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDFLAGS) $(Q) $(CROSS)size $@ $(STUB_OBJ): $(SRCS) $(STUB_OBJ_DEPS) @@ -94,6 +95,9 @@ $(STUB_IMAGE_HDR): $(STUB_ELF) $(Q) $(CROSS)readelf -S $^ | fgrep .bss | awk '{print $$7"UL"}' >> $(STUB_IMAGE_HDR) $(Q) @printf "\\n#define $(STUB_CHIP)_STUB_ENTRY_ADDR 0x0" >> $(STUB_IMAGE_HDR) $(Q) $(CROSS)readelf -s $^ | fgrep stub_main | awk '{print $$2"UL"}' >> $(STUB_IMAGE_HDR) + $(Q) @printf "\\n#define $(STUB_CHIP)_STUB_APPTRACE_CTRL_ADDR 0x0" >> $(STUB_IMAGE_HDR) + $(Q) $(CROSS)readelf -s $^ | fgrep s_tracing_ctrl | awk '{print $$2"UL"}' >> $(STUB_IMAGE_HDR) + $(Q) @printf "\n" >> $(STUB_CHIP_PATH)/$(STUB_IMAGE_HDR) $(Q) @printf "/*#define $(STUB_CHIP)_STUB_BUILD_IDF_REV " >> $(STUB_IMAGE_HDR) $(Q) cd $(IDF_PATH); git rev-parse --short HEAD >> $(STUB_CHIP_PATH)/$(STUB_IMAGE_HDR) $(Q) @printf "*/\n" >> $(STUB_IMAGE_HDR) diff --git a/contrib/loaders/flash/esp/stub_flasher.c b/contrib/loaders/flash/esp/stub_flasher.c index 8755d82ab0..f876a929d4 100644 --- a/contrib/loaders/flash/esp/stub_flasher.c +++ b/contrib/loaders/flash/esp/stub_flasher.c @@ -21,8 +21,6 @@ #include #include -#include "eri.h" -#include "trax.h" #include "esp_app_trace.h" #include "esp_flash_partitions.h" #include "esp_image_format.h" @@ -33,24 +31,9 @@ #define STUB_DEBUG 0 -#define STUB_BP_INSN_SECT_BUF_SIZE (2*STUB_FLASH_SECTOR_SIZE) - -#define ESP_APPTRACE_TRAX_BLOCK_SIZE (0x4000UL) -#define ESP_APPTRACE_USR_DATA_LEN_MAX (ESP_APPTRACE_TRAX_BLOCK_SIZE - 2) - -#define ESP_APPTRACE_TRAX_CTRL_REG ERI_TRAX_DELAYCNT -#define ESP_APPTRACE_TRAX_HOST_CONNECT (1 << 23) - -#define XT_INS_BREAK 0x004000 -#define XT_INS_BREAKN 0xF02D - +#define STUB_BP_INSN_SECT_BUF_SIZE (2*STUB_FLASH_SECTOR_SIZE) #define MHZ (1000000) -#ifdef XT_CLOCK_FREQ -#undef XT_CLOCK_FREQ -#endif -#define XT_CLOCK_FREQ (g_stub_cpu_freq_hz) -#define CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/MHZ)) extern void stub_flash_state_prepare(struct stub_flash_state *state); extern void stub_flash_state_restore(struct stub_flash_state *state); @@ -61,6 +44,15 @@ extern uint32_t _bss_end; /* g_ticks_us defined in ROMs for PRO and APP CPU */ extern uint32_t g_ticks_per_us_pro; +extern uint32_t stub_flash_get_id(void); +extern void stub_flash_cache_flush(void); +extern void stub_flash_state_prepare(struct stub_flash_state *state); +extern void stub_flash_state_restore(struct stub_flash_state *state); +extern void stub_clock_configure(void); +extern void stub_uart_console_configure(void); +extern int stub_apptrace_prepare(void); +extern uint64_t stub_get_time(void); + static struct { /* offset of next flash write */ uint32_t next_write; @@ -94,15 +86,16 @@ void __assert_func(const char *path, int line, const char *func, const char *msg while (1) ; } -static inline uint8_t xtensa_get_insn_size(uint8_t *insn) +void abort(void) { - return insn[0] & 0x8 ? 2 : 3; + STUB_LOGE("ABORT\n"); + while (1) ; } #if STUB_DEBUG static int stub_flash_test(void) { - int ret = ESP_XTENSA_STUB_ERR_OK; + int ret = ESP_STUB_ERR_OK; uint8_t buf[32] = {9, 1, 2, 3, 4, 5, 6, 8}; uint32_t flash_addr = 0x1d4000; @@ -110,19 +103,19 @@ static int stub_flash_test(void) flash_addr / STUB_FLASH_SECTOR_SIZE); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to erase flash (%d)\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } rc = esp_rom_spiflash_write(flash_addr, (uint32_t *)buf, sizeof(buf)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to write flash (%d)\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } rc = esp_rom_spiflash_read(flash_addr, (uint32_t *)buf, sizeof(buf)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read flash (%d)\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGD("Data: "); @@ -140,32 +133,27 @@ static int stub_apptrace_init() esp_err_t err = esp_apptrace_init(); if (err != ESP_OK) { STUB_LOGE("Failed to init apptrace module (%d)!\n", err); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - /* imply that host is auto-connected */ - uint32_t reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); - reg |= ESP_APPTRACE_TRAX_HOST_CONNECT; - eri_write(ESP_APPTRACE_TRAX_CTRL_REG, reg); - - return ESP_XTENSA_STUB_ERR_OK; + return stub_apptrace_prepare(); } static int stub_flash_calc_hash(uint32_t addr, uint32_t size, uint8_t *hash) { esp_rom_spiflash_result_t rc; uint32_t rd_cnt = 0, rd_sz = 0; - uint8_t read_buf[ESP_XTENSA_STUB_RDWR_BUFF_SIZE]; + uint8_t read_buf[ESP_STUB_RDWR_BUFF_SIZE]; STUB_LOGD("stub_flash_calc_hash %d bytes @ 0x%x\n", size, addr); stub_sha256_start(); while (size > 0) { - rd_sz = MIN(ESP_XTENSA_STUB_RDWR_BUFF_SIZE, size); + rd_sz = MIN(ESP_STUB_RDWR_BUFF_SIZE, size); rc = stub_flash_read_buff(addr + rd_cnt, (uint32_t *)read_buf, rd_sz); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read flash (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } stub_sha256_data(read_buf, rd_sz); size -= rd_sz; @@ -178,7 +166,7 @@ static int stub_flash_calc_hash(uint32_t addr, uint32_t size, uint8_t *hash) hash[0], hash[1], hash[2], hash[29], hash[30], hash[31]); - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_flash_read(uint32_t addr, uint32_t size) @@ -186,8 +174,14 @@ static int stub_flash_read(uint32_t addr, uint32_t size) esp_rom_spiflash_result_t rc; uint32_t total_cnt = 0; +#if CONFIG_STUB_STACK_DATA_POOL_SIZE > 0 + /* stub_apptrace_init alloc up buffers on stack */ + uint8_t stack_data_pool[CONFIG_STUB_STACK_DATA_POOL_SIZE]; + stub_stack_data_pool_init(stack_data_pool, sizeof(stack_data_pool)); +#endif + int ret = stub_apptrace_init(); - if (ret != ESP_XTENSA_STUB_ERR_OK) + if (ret != ESP_STUB_ERR_OK) return ret; STUB_LOGI("Start reading %d bytes @ 0x%x\n", size, addr); @@ -200,25 +194,25 @@ static int stub_flash_read(uint32_t addr, uint32_t size) rd_sz &= ~0x3UL; if (rd_sz == 0) break; - uint32_t start = xthal_get_ccount(); + uint64_t start = stub_get_time(); uint8_t *buf = esp_apptrace_buffer_get(ESP_APPTRACE_DEST_TRAX, rd_sz, ESP_APPTRACE_TMO_INFINITE); if (!buf) { STUB_LOGE("Failed to get trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - uint32_t end = xthal_get_ccount(); - STUB_LOGD("Got trace buf %d bytes @ 0x%x in %d ms\n", rd_sz, buf, - CPUTICKS2US(end - start) / 1000); + uint64_t end = stub_get_time(); + STUB_LOGD("Got trace buf %d bytes @ 0x%x in %lld us\n", rd_sz, buf, + end - start); - start = xthal_get_ccount(); + start = stub_get_time(); rc = stub_flash_read_buff(addr + total_cnt, (uint32_t *)buf, rd_sz); - end = xthal_get_ccount(); + end = stub_get_time(); STUB_LOGD("Read flash @ 0x%x sz %d in %d ms\n", addr + total_cnt, rd_sz, - CPUTICKS2US(end - start) / 1000); + end - start); /* regardless of the read result, first free the buffer */ esp_err_t err = esp_apptrace_buffer_put(ESP_APPTRACE_DEST_TRAX, @@ -228,12 +222,12 @@ static int stub_flash_read(uint32_t addr, uint32_t size) /* now check the read result */ if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read flash (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } if (err != ESP_OK) { STUB_LOGE("Failed to put trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } total_cnt += rd_sz; @@ -244,7 +238,7 @@ static int stub_flash_read(uint32_t addr, uint32_t size) err = esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TMO_INFINITE); if (err != ESP_OK) { STUB_LOGE("Failed to flush trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGD("Sent trace buf %d bytes @ 0x%x\n", rd_sz, buf); } @@ -252,7 +246,7 @@ static int stub_flash_read(uint32_t addr, uint32_t size) if (total_cnt < size) { if ((size - total_cnt) >= 4) { STUB_LOGE("Exited loop when remaing data size is more the 4 bytes!\n"); - return ESP_XTENSA_STUB_ERR_FAIL;/*should never get here*/ + return ESP_STUB_ERR_FAIL; /*should never get here*/ } /* if we exited loop because remaing data size is less than 4 bytes */ uint8_t last_bytes[4]; @@ -260,14 +254,14 @@ static int stub_flash_read(uint32_t addr, uint32_t size) STUB_LOGD("Read padded word from flash @ 0x%x\n", addr + total_cnt); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read last word from flash (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } uint8_t *buf = esp_apptrace_buffer_get(ESP_APPTRACE_DEST_TRAX, size - total_cnt, ESP_APPTRACE_TMO_INFINITE); if (!buf) { STUB_LOGE("Failed to get trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } memcpy(buf, last_bytes, size - total_cnt); esp_err_t err = esp_apptrace_buffer_put(ESP_APPTRACE_DEST_TRAX, @@ -275,7 +269,7 @@ static int stub_flash_read(uint32_t addr, uint32_t size) ESP_APPTRACE_TMO_INFINITE); if (err != ESP_OK) { STUB_LOGE("Failed to put trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGD("Flush trace buf %d bytes @ 0x%x [%x %x %x %x %x %x %x %x]\n", size - total_cnt, buf, buf[-4], buf[-3], buf[-2], buf[-1], @@ -283,13 +277,13 @@ static int stub_flash_read(uint32_t addr, uint32_t size) err = esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TMO_INFINITE); if (err != ESP_OK) { STUB_LOGE("Failed to flush trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGE("Sent last trace buf %d bytes @ 0x%x\n", size - total_cnt, buf); } STUB_LOGD("Read %d bytes @ 0x%x\n", size, addr); - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static esp_rom_spiflash_result_t stub_spiflash_write(uint32_t spi_flash_addr, @@ -298,17 +292,17 @@ static esp_rom_spiflash_result_t stub_spiflash_write(uint32_t spi_flash_addr, { esp_rom_spiflash_result_t rc; - uint32_t start = xthal_get_ccount(); + uint64_t start = stub_get_time(); if (stub_get_flash_encryption_mode() != ESP_FLASH_ENC_MODE_DISABLED) rc = esp_rom_spiflash_write_encrypted(spi_flash_addr, data, len); else rc = esp_rom_spiflash_write(spi_flash_addr, data, len); - uint32_t end = xthal_get_ccount(); + uint64_t end = stub_get_time(); STUB_LOGD("Write flash @ 0x%x sz %d in %d us\n", spi_flash_addr, len, - CPUTICKS2US(end - start)); + end - start); return rc; } @@ -319,8 +313,8 @@ static int stub_write_aligned_buffer(void *data_buf, uint32_t length) uint32_t out_bytes = length; uint32_t bytes_in_out_buf = s_fs.next_out - s_fs.out_buf; - if (out_bytes + bytes_in_out_buf > ESP_XTENSA_STUB_UNZIP_BUFF_SIZE) - out_bytes = ESP_XTENSA_STUB_UNZIP_BUFF_SIZE - bytes_in_out_buf; + if (out_bytes + bytes_in_out_buf > ESP_STUB_UNZIP_BUFF_SIZE) + out_bytes = ESP_STUB_UNZIP_BUFF_SIZE - bytes_in_out_buf; memcpy(s_fs.out_buf + bytes_in_out_buf, data_buf, out_bytes); @@ -330,16 +324,16 @@ static int stub_write_aligned_buffer(void *data_buf, uint32_t length) s_fs.next_out += out_bytes; if (s_fs.remaining_uncompressed - bytes_in_out_buf == 0 || - bytes_in_out_buf == ESP_XTENSA_STUB_UNZIP_BUFF_SIZE) { + bytes_in_out_buf == ESP_STUB_UNZIP_BUFF_SIZE) { uint32_t wr_sz = bytes_in_out_buf; /* add padding if this is the last package */ - if (bytes_in_out_buf < ESP_XTENSA_STUB_UNZIP_BUFF_SIZE) { + if (bytes_in_out_buf < ESP_STUB_UNZIP_BUFF_SIZE) { memset(s_fs.out_buf + bytes_in_out_buf, 0xFF, - ESP_XTENSA_STUB_UNZIP_BUFF_SIZE - bytes_in_out_buf); - wr_sz = ESP_XTENSA_STUB_UNZIP_BUFF_SIZE; + ESP_STUB_UNZIP_BUFF_SIZE - bytes_in_out_buf); + wr_sz = ESP_STUB_UNZIP_BUFF_SIZE; } /* write buffer with aligned size */ @@ -348,7 +342,7 @@ static int stub_write_aligned_buffer(void *data_buf, uint32_t length) if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to write flash (%d)\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } /* change counters using unpadding len */ @@ -358,27 +352,34 @@ static int stub_write_aligned_buffer(void *data_buf, uint32_t length) } } - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_flash_write(void *args) { uint32_t total_cnt = 0; uint8_t *buf = NULL; - struct esp_xtensa_stub_flash_write_args *wargs = - (struct esp_xtensa_stub_flash_write_args *)args; + struct esp_flash_stub_flash_write_args *wargs = + (struct esp_flash_stub_flash_write_args *)args; STUB_LOGD("Start writing %d bytes @ 0x%x\n", wargs->size, wargs->start_addr); +#if CONFIG_STUB_STACK_DATA_POOL_SIZE > 0 + /* for non-xtensa chips stub_apptrace_init alloc up buffers on stack, xtensa chips uses TRAX + *memory */ + uint8_t stack_data_pool[CONFIG_STUB_STACK_DATA_POOL_SIZE]; + stub_stack_data_pool_init(stack_data_pool, sizeof(stack_data_pool)); +#endif + int ret = stub_apptrace_init(); - if (ret != ESP_XTENSA_STUB_ERR_OK) + if (ret != ESP_STUB_ERR_OK) return ret; STUB_LOGI("Init apptrace module down buffer %d bytes @ 0x%x\n", wargs->down_buf_size, wargs->down_buf_addr); esp_apptrace_down_buffer_config((uint8_t *)wargs->down_buf_addr, wargs->down_buf_size); - uint8_t out_buf[ESP_XTENSA_STUB_UNZIP_BUFF_SIZE]; + uint8_t out_buf[ESP_STUB_UNZIP_BUFF_SIZE]; s_fs.next_write = wargs->start_addr; s_fs.remaining_uncompressed = wargs->total_size; s_fs.out_buf = out_buf; @@ -390,19 +391,19 @@ static int stub_flash_write(void *args) wr_sz, wargs->size, total_cnt, - CPUTICKS2US(xthal_get_ccount())); - uint32_t start = xthal_get_ccount(); + stub_get_time()); + uint32_t start = stub_get_time(); buf = esp_apptrace_down_buffer_get(ESP_APPTRACE_DEST_TRAX, &wr_sz, ESP_APPTRACE_TMO_INFINITE); if (!buf) { STUB_LOGE("Failed to get trace down buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - uint32_t end = xthal_get_ccount(); + uint32_t end = stub_get_time(); STUB_LOGD("Got trace down buf %d bytes @ 0x%x in %d us\n", wr_sz, buf, - CPUTICKS2US(end - start)); + end - start); ret = stub_write_aligned_buffer(buf, wr_sz); @@ -413,18 +414,18 @@ static int stub_flash_write(void *args) if (err != ESP_OK) { STUB_LOGE("Failed to put trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } /* now check the write result */ - if (ret != ESP_XTENSA_STUB_ERR_OK) - return ESP_XTENSA_STUB_ERR_INFLATE; + if (ret != ESP_STUB_ERR_OK) + return ESP_STUB_ERR_INFLATE; total_cnt += wr_sz; } STUB_LOGD("Wrote %d bytes @ 0x%x\n", wargs->total_size, wargs->start_addr); - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_write_inflated_data(void *data_buf, uint32_t length) @@ -436,16 +437,16 @@ static int stub_write_inflated_data(void *data_buf, uint32_t length) } if (length == 0) - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; /* add padding if this is the last package */ - if (length < ESP_XTENSA_STUB_UNZIP_BUFF_SIZE) { + if (length < ESP_STUB_UNZIP_BUFF_SIZE) { if (s_fs.remaining_uncompressed - length == 0) { - memset(data_buf + length, 0xFF, ESP_XTENSA_STUB_UNZIP_BUFF_SIZE - length); - length = ESP_XTENSA_STUB_UNZIP_BUFF_SIZE; + memset(data_buf + length, 0xFF, ESP_STUB_UNZIP_BUFF_SIZE - length); + length = ESP_STUB_UNZIP_BUFF_SIZE; } else { STUB_LOGE("Unaligned offset! %d\n", length); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } } @@ -455,10 +456,10 @@ static int stub_write_inflated_data(void *data_buf, uint32_t length) length); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to write flash (%d)\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_run_inflator(void *data_buf, uint32_t length) @@ -469,21 +470,21 @@ static int stub_run_inflator(void *data_buf, uint32_t length) /* input remaining */ size_t in_bytes = length; /* output space remaining */ - size_t out_bytes = s_fs.out_buf + ESP_XTENSA_STUB_UNZIP_BUFF_SIZE - s_fs.next_out; + size_t out_bytes = s_fs.out_buf + ESP_STUB_UNZIP_BUFF_SIZE - s_fs.next_out; int flags = 0; if (s_fs.remaining_compressed > length) flags |= TINFL_FLAG_HAS_MORE_INPUT; - uint32_t start = xthal_get_ccount(); + uint64_t start = stub_get_time(); status = tinfl_decompress(s_fs.inflator, data_buf, &in_bytes, s_fs.out_buf, s_fs.next_out, &out_bytes, flags); - uint32_t end = xthal_get_ccount(); - STUB_LOGD("tinfl_decompress in(%d) out(%d) (%d)us\n", + uint64_t end = stub_get_time(); + STUB_LOGD("tinfl_decompress in(%d) out(%d) (%lld)us\n", in_bytes, out_bytes, - CPUTICKS2US(end - start)); + end - start); s_fs.remaining_compressed -= in_bytes; length -= in_bytes; @@ -492,11 +493,11 @@ static int stub_run_inflator(void *data_buf, uint32_t length) size_t bytes_in_out_buf = s_fs.next_out - s_fs.out_buf; if (status <= TINFL_STATUS_DONE || - bytes_in_out_buf == ESP_XTENSA_STUB_UNZIP_BUFF_SIZE) { + bytes_in_out_buf == ESP_STUB_UNZIP_BUFF_SIZE) { /* Output buffer full, or done */ if (stub_write_inflated_data(s_fs.out_buf, - bytes_in_out_buf) != ESP_XTENSA_STUB_ERR_OK) - return ESP_XTENSA_STUB_ERR_FAIL; + bytes_in_out_buf) != ESP_STUB_ERR_OK) + return ESP_STUB_ERR_FAIL; s_fs.next_write += bytes_in_out_buf; s_fs.remaining_uncompressed -= bytes_in_out_buf; @@ -506,30 +507,37 @@ static int stub_run_inflator(void *data_buf, uint32_t length) if (status < TINFL_STATUS_DONE) { STUB_LOGE("Failed to inflate data (%d)\n", status); - return ESP_XTENSA_STUB_ERR_INFLATE; + return ESP_STUB_ERR_INFLATE; } if (status == TINFL_STATUS_DONE && s_fs.remaining_uncompressed > 0) { STUB_LOGE("Not enough compressed data\n"); - return ESP_XTENSA_STUB_ERR_NOT_ENOUGH_DATA; + return ESP_STUB_ERR_NOT_ENOUGH_DATA; } if (status != TINFL_STATUS_DONE && s_fs.remaining_uncompressed == 0) { STUB_LOGE("Too much compressed data\n"); - return ESP_XTENSA_STUB_ERR_TOO_MUCH_DATA; + return ESP_STUB_ERR_TOO_MUCH_DATA; } - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_flash_write_deflated(void *args) { uint32_t total_cnt = 0; uint8_t *buf = NULL; - struct esp_xtensa_stub_flash_write_args *wargs = - (struct esp_xtensa_stub_flash_write_args *)args; + struct esp_flash_stub_flash_write_args *wargs = + (struct esp_flash_stub_flash_write_args *)args; STUB_LOGD("Start writing deflated %d bytes @ 0x%x\n", wargs->size, wargs->start_addr); +#if CONFIG_STUB_STACK_DATA_POOL_SIZE > 0 + /* for non-xtensa chips stub_apptrace_init alloc up buffers on stack, xtensa chips uses TRAX + *memory */ + uint8_t stack_data_pool[CONFIG_STUB_STACK_DATA_POOL_SIZE]; + stub_stack_data_pool_init(stack_data_pool, sizeof(stack_data_pool)); +#endif + int ret = stub_apptrace_init(); - if (ret != ESP_XTENSA_STUB_ERR_OK) + if (ret != ESP_STUB_ERR_OK) return ret; STUB_LOGI("Init apptrace module down buffer %d bytes @ 0x%x\n", @@ -541,7 +549,7 @@ static int stub_flash_write_deflated(void *args) /* both of them must be in stack! */ tinfl_decompressor inflator; - uint8_t out_buf[ESP_XTENSA_STUB_UNZIP_BUFF_SIZE]; + uint8_t out_buf[ESP_STUB_UNZIP_BUFF_SIZE]; /* */ s_fs.next_write = wargs->start_addr; @@ -558,21 +566,22 @@ static int stub_flash_write_deflated(void *args) wr_sz, wargs->size, total_cnt, - CPUTICKS2US(xthal_get_ccount())); - uint32_t start = xthal_get_ccount(); + stub_get_time()); + uint64_t start = stub_get_time(); buf = esp_apptrace_down_buffer_get(ESP_APPTRACE_DEST_TRAX, &wr_sz, ESP_APPTRACE_TMO_INFINITE); if (!buf) { STUB_LOGE("Failed to get trace down buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - uint32_t end = xthal_get_ccount(); + uint64_t end = stub_get_time(); STUB_LOGD("Got trace down buf %d bytes @ 0x%x in %d us\n", wr_sz, buf, - CPUTICKS2US(end - start)); + end - start); - ret = stub_run_inflator(buf, wr_sz); + if (stub_run_inflator(buf, wr_sz) != ESP_STUB_ERR_OK) + return ESP_STUB_ERR_INFLATE; /* regardless of the write result, first free the buffer */ esp_err_t err = esp_apptrace_down_buffer_put(ESP_APPTRACE_DEST_TRAX, @@ -581,23 +590,23 @@ static int stub_flash_write_deflated(void *args) if (err != ESP_OK) { STUB_LOGE("Failed to put trace buf!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } /* now check the write result */ - if (ret != ESP_XTENSA_STUB_ERR_OK) - return ESP_XTENSA_STUB_ERR_INFLATE; + if (ret != ESP_STUB_ERR_OK) + return ESP_STUB_ERR_INFLATE; total_cnt += wr_sz; } STUB_LOGD("Wrote %d bytes @ 0x%x\n", wargs->total_size, wargs->start_addr); - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_flash_erase(uint32_t flash_addr, uint32_t size) { - int ret = ESP_XTENSA_STUB_ERR_OK; + int ret = ESP_STUB_ERR_OK; if (flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) flash_addr &= ~(STUB_FLASH_SECTOR_SIZE - 1); @@ -606,21 +615,21 @@ static int stub_flash_erase(uint32_t flash_addr, uint32_t size) size = (size + (STUB_FLASH_SECTOR_SIZE - 1)) & ~(STUB_FLASH_SECTOR_SIZE - 1); STUB_LOGD("erase flash @ 0x%x, sz %d\n", flash_addr, size); - uint32_t start = xthal_get_ccount(); + uint64_t start = stub_get_time(); esp_rom_spiflash_result_t rc = esp_rom_spiflash_erase_area(flash_addr, size); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to erase flash (%d)\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - uint32_t end = xthal_get_ccount(); - STUB_LOGD("Erased %d bytes @ 0x%x in %d ms\n", size, flash_addr, - CPUTICKS2US(end - start) / 1000); + uint64_t end = stub_get_time(); + STUB_LOGD("Erased %d bytes @ 0x%x in %lld ms\n", size, flash_addr, + end - start / 1000); return ret; } static int stub_flash_erase_check(uint32_t start_sec, uint32_t sec_num, uint8_t *sec_erased) { - int ret = ESP_XTENSA_STUB_ERR_OK; + int ret = ESP_STUB_ERR_OK; uint8_t buf[STUB_FLASH_SECTOR_SIZE / 8];/* implying that sector size is multiple of * sizeof(buf) */ @@ -635,7 +644,7 @@ static int stub_flash_erase_check(uint32_t start_sec, uint32_t sec_num, uint8_t sizeof(buf)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read flash (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } for (int n = 0; n < sizeof(buf); n++) { if (buf[n] != 0xFF) { @@ -681,7 +690,7 @@ static inline bool stub_flash_should_map(uint32_t load_addr) || (load_addr >= SOC_DROM_LOW && load_addr < SOC_DROM_HIGH); } -static int stub_flash_get_app_mappings(uint32_t off, struct esp_xtensa_flash_mapping *flash_map) +static int stub_flash_get_app_mappings(uint32_t off, struct esp_flash_mapping *flash_map) { esp_image_header_t img_hdr; uint16_t maps_num = 0; @@ -690,11 +699,11 @@ static int stub_flash_get_app_mappings(uint32_t off, struct esp_xtensa_flash_map stub_flash_read_buff(off, (uint32_t *)&img_hdr, sizeof(img_hdr)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read app image header (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } if (img_hdr.magic != ESP_IMAGE_HEADER_MAGIC) { STUB_LOGE("Invalid magic number 0x%x in app image!\n", img_hdr.magic); - return ESP_XTENSA_STUB_ERR_INVALID_IMAGE; + return ESP_STUB_ERR_FAIL; } STUB_LOGI("Found app image: magic 0x%x, %d segments, entry @ 0x%x\n", @@ -707,7 +716,7 @@ static int stub_flash_get_app_mappings(uint32_t off, struct esp_xtensa_flash_map rc = stub_flash_read_buff(flash_addr, (uint32_t *)&seg_hdr, sizeof(seg_hdr)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read app segment header (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGI("App segment %d: %d bytes @ 0x%x\n", k, @@ -719,7 +728,7 @@ static int stub_flash_get_app_mappings(uint32_t off, struct esp_xtensa_flash_map seg_hdr.data_len, flash_addr + sizeof(seg_hdr), seg_hdr.load_addr); - if (maps_num < ESP_XTENSA_STUB_FLASH_MAPPINGS_MAX_NUM) { + if (maps_num < ESP_STUB_FLASH_MAPPINGS_MAX_NUM) { flash_map->maps[maps_num].phy_addr = flash_addr + sizeof(seg_hdr); flash_map->maps[maps_num].load_addr = seg_hdr.load_addr; flash_map->maps[maps_num].size = seg_hdr.data_len; @@ -730,14 +739,14 @@ static int stub_flash_get_app_mappings(uint32_t off, struct esp_xtensa_flash_map flash_addr += sizeof(seg_hdr) + seg_hdr.data_len; } flash_map->maps_num = maps_num; - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_flash_get_map(uint32_t app_off, uint32_t maps_addr) { esp_rom_spiflash_result_t rc; esp_partition_info_t part; - struct esp_xtensa_flash_mapping *flash_map = (struct esp_xtensa_flash_mapping *)maps_addr; + struct esp_flash_mapping *flash_map = (struct esp_flash_mapping *)maps_addr; uint32_t flash_size = stub_flash_get_size(); STUB_LOGD("%s: 0x%x 0x%x\n", __func__, app_off, maps_addr); @@ -751,12 +760,12 @@ static int stub_flash_get_map(uint32_t app_off, uint32_t maps_addr) (uint32_t *)&part, sizeof(part)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { - STUB_LOGE("Failed to read partitions table entry (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + STUB_LOGE("Failed to read partitions table entrt (%d)!\n", rc); + return ESP_STUB_ERR_FAIL; } if (part.magic != ESP_PARTITION_MAGIC) { STUB_LOGE("Invalid partition table magic! (0x%x)\n", part.magic); - return ESP_XTENSA_STUB_ERR_INVALID_IMAGE; + return ESP_STUB_ERR_INVALID_IMAGE; } if (part.pos.offset > flash_size || part.pos.offset + part.pos.size > flash_size) { STUB_LOGE( @@ -765,7 +774,7 @@ static int stub_flash_get_map(uint32_t app_off, uint32_t maps_addr) part.pos.offset, part.pos.size, flash_size); - return ESP_XTENSA_STUB_ERR_INVALID_IMAGE; + return ESP_STUB_ERR_FAIL; } STUB_LOGD("Found partition %d, m 0x%x, t 0x%x, st 0x%x, l '%s'\n", i, @@ -782,7 +791,7 @@ static int stub_flash_get_map(uint32_t app_off, uint32_t maps_addr) } } /* PART_TYPE_APP not found */ - return ESP_XTENSA_STUB_ERR_INVALID_IMAGE; + return ESP_STUB_ERR_OK; } /** @@ -809,7 +818,7 @@ static uint8_t stub_flash_set_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, return 0; } uint8_t insn_sz = - xtensa_get_insn_size(&insn_sect[bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)]); + stub_get_insn_size(&insn_sect[bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)]); memcpy((void *)insn_buf_addr, &insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1))], insn_sz); @@ -821,7 +830,7 @@ static uint8_t stub_flash_set_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, bp_flash_addr); /* this will erase full sector or two */ - if (stub_flash_erase(bp_flash_addr, insn_sz) != ESP_XTENSA_STUB_ERR_OK) { + if (stub_flash_erase(bp_flash_addr, insn_sz) != ESP_STUB_ERR_OK) { STUB_LOGE("Failed to erase insn sector!\n"); return 0; } @@ -829,7 +838,7 @@ static uint8_t stub_flash_set_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, uint32_t d32; uint8_t d8[4]; } break_insn; - break_insn.d32 = insn_sz == 2 ? XT_INS_BREAKN : XT_INS_BREAK; + break_insn.d32 = stub_get_break_insn(insn_sz); insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) + 0] = break_insn.d8[0]; insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) + 1] = break_insn.d8[1]; if (insn_sz == 3) @@ -849,7 +858,7 @@ static uint8_t stub_flash_set_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, rc = stub_flash_read_buff(bp_flash_addr & ~0x3UL, (uint32_t *)tmp, sizeof(tmp)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read insn (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGD("%s: WROTE 0x%x 0x%x [%02x %02x %02x %02x %02x %02x %02x %02x]\n", __func__, @@ -887,24 +896,26 @@ static int stub_flash_clear_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, u STUB_BP_INSN_SECT_BUF_SIZE); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read insn sector (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } - uint8_t insn_sz = xtensa_get_insn_size(insn); + uint8_t insn_sz = stub_get_insn_size(insn); /* this will erase full sector or two */ - if (stub_flash_erase(bp_flash_addr, insn_sz) != ESP_XTENSA_STUB_ERR_OK) { + if (stub_flash_erase(bp_flash_addr, insn_sz) != ESP_STUB_ERR_OK) { STUB_LOGE("Failed to erase insn sector!\n"); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) + 0] = insn[0]; insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) + 1] = insn[1]; if (insn_sz == 3) insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) + 2] = insn[2]; + if (insn_sz == 4) + insn_sect[(bp_flash_addr & (STUB_FLASH_SECTOR_SIZE - 1)) + 3] = insn[3]; rc = stub_spiflash_write(bp_flash_addr & ~(STUB_FLASH_SECTOR_SIZE - 1), (uint32_t *)insn_sect, STUB_BP_INSN_SECT_BUF_SIZE); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to restore insn (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } stub_flash_cache_flush(); @@ -914,7 +925,7 @@ static int stub_flash_clear_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, u rc = stub_flash_read_buff(bp_flash_addr & ~0x3UL, (uint32_t *)tmp, sizeof(tmp)); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to read insn (%d)!\n", rc); - return ESP_XTENSA_STUB_ERR_FAIL; + return ESP_STUB_ERR_FAIL; } STUB_LOGD("%s: WROTE 0x%x 0x%x [%02x %02x %02x %02x %02x %02x %02x %02x]\n", __func__, @@ -929,12 +940,12 @@ static int stub_flash_clear_bp(uint32_t bp_flash_addr, uint32_t insn_buf_addr, u tmp[6], tmp[7]); #endif - return ESP_XTENSA_STUB_ERR_OK; + return ESP_STUB_ERR_OK; } static int stub_flash_handler(int cmd, va_list ap) { - int ret = ESP_XTENSA_STUB_ERR_OK; + int ret = ESP_STUB_ERR_OK; struct stub_flash_state flash_state; uint32_t arg1 = va_arg(ap, uint32_t); /* flash_addr, start_sect */ uint32_t arg2 = va_arg(ap, uint32_t); /* number of sectors */ @@ -947,10 +958,10 @@ static int stub_flash_handler(int cmd, va_list ap) uint32_t flash_size = stub_flash_get_size(); if (flash_size == 0) { STUB_LOGE("Failed to get flash size!\n"); - ret = cmd == ESP_XTENSA_STUB_CMD_FLASH_SIZE ? 0 : ESP_XTENSA_STUB_ERR_FAIL; + ret = cmd == ESP_STUB_CMD_FLASH_SIZE ? 0 : ESP_STUB_ERR_FAIL; goto _flash_end; } - if (cmd == ESP_XTENSA_STUB_CMD_FLASH_SIZE) { + if (cmd == ESP_STUB_CMD_FLASH_SIZE) { ret = flash_size; goto _flash_end; } @@ -964,51 +975,53 @@ static int stub_flash_handler(int cmd, va_list ap) esp_rom_spiflash_result_t rc = esp_rom_spiflash_unlock(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { STUB_LOGE("Failed to unlock flash (%d)\n", rc); - ret = ESP_XTENSA_STUB_ERR_FAIL; + ret = ESP_STUB_ERR_FAIL; goto _flash_end; } + STUB_LOGD("%s 1\n", __func__); + switch (cmd) { - case ESP_XTENSA_STUB_CMD_FLASH_READ: + case ESP_STUB_CMD_FLASH_READ: ret = stub_flash_read(arg1, arg2); break; - case ESP_XTENSA_STUB_CMD_FLASH_ERASE: + case ESP_STUB_CMD_FLASH_ERASE: ret = stub_flash_erase(arg1, arg2); break; - case ESP_XTENSA_STUB_CMD_FLASH_ERASE_CHECK: + case ESP_STUB_CMD_FLASH_ERASE_CHECK: ret = stub_flash_erase_check(arg1, arg2, arg3); break; - case ESP_XTENSA_STUB_CMD_FLASH_WRITE: + case ESP_STUB_CMD_FLASH_WRITE: ret = stub_flash_write((void *)arg1); break; - case ESP_XTENSA_STUB_CMD_FLASH_WRITE_DEFLATED: + case ESP_STUB_CMD_FLASH_WRITE_DEFLATED: ret = stub_flash_write_deflated((void *)arg1); break; - case ESP_XTENSA_STUB_CMD_FLASH_CALC_HASH: + case ESP_STUB_CMD_FLASH_CALC_HASH: ret = stub_flash_calc_hash(arg1, arg2, arg3); break; - case ESP_XTENSA_STUB_CMD_FLASH_MAP_GET: + case ESP_STUB_CMD_FLASH_MAP_GET: ret = stub_flash_get_map(arg1, arg2); break; - case ESP_XTENSA_STUB_CMD_FLASH_BP_SET: + case ESP_STUB_CMD_FLASH_BP_SET: ret = stub_flash_set_bp(arg1, arg2, arg3); break; - case ESP_XTENSA_STUB_CMD_FLASH_BP_CLEAR: + case ESP_STUB_CMD_FLASH_BP_CLEAR: ret = stub_flash_clear_bp(arg1, arg2, arg3); break; - case ESP_XTENSA_STUB_CMD_CLOCK_CONFIGURE: + case ESP_STUB_CMD_CLOCK_CONFIGURE: ret = stub_cpu_clock_configure(arg1); #if STUB_LOG_LOCAL_LEVEL > STUB_LOG_NONE stub_uart_console_configure(); #endif break; #if STUB_DEBUG - case ESP_XTENSA_STUB_CMD_FLASH_TEST: + case ESP_STUB_CMD_FLASH_TEST: ret = stub_flash_test(); break; #endif default: - ret = ESP_XTENSA_STUB_ERR_NOT_SUPPORTED; + ret = ESP_STUB_ERR_NOT_SUPPORTED; } _flash_end: @@ -1021,6 +1034,24 @@ void ets_update_cpu_frequency(uint32_t ticks_per_us) /* do nothing for stub */ } +__attribute__((weak)) int stub_cpu_clock_configure(int cpu_freq_mhz) +{ + return 0; +} + +__attribute__((weak)) void stub_uart_console_configure(void) +{ +} + +__attribute__((weak)) esp_flash_enc_mode_t stub_get_flash_encryption_mode(void) +{ + return ESP_FLASH_ENC_MODE_DISABLED; +} + +__attribute__((weak)) void stub_print_cache_mmu_registers(void) +{ +} + int stub_main(int cmd, ...) { va_list ap; @@ -1035,27 +1066,25 @@ int stub_main(int cmd, ...) /* interrupts level in PS is set to 5 to allow high prio IRQs only (including Debug * Interrupt) */ /* We need Debug Interrupt Level to allow breakpoints handling by OpenOCD */ -#if STUB_LOG_LOCAL_LEVEL > STUB_LOG_NONE stub_cpu_clock_configure(-1); stub_uart_console_configure(); - STUB_LOGD("cpu_freq:%d Mhz\n", XT_CLOCK_FREQ/MHZ); + STUB_LOGD("cpu_freq:%d Mhz\n", stub_esp_clk_cpu_freq()/MHZ); stub_print_cache_mmu_registers(); -#endif STUB_LOGD("BSS 0x%x..0x%x\n", &_bss_start, &_bss_end); STUB_LOGD("cmd %d\n", cmd); va_start(ap, cmd); - if (cmd <= ESP_XTENSA_STUB_CMD_FLASH_MAX_ID) + if (cmd <= ESP_STUB_CMD_FLASH_MAX_ID) ret = stub_flash_handler(cmd, ap); else switch (cmd) { #if STUB_DEBUG - case ESP_XTENSA_STUB_CMD_TEST: + case ESP_STUB_CMD_TEST: STUB_LOGD("TEST %d\n", cmd); break; #endif default: - ret = ESP_XTENSA_STUB_ERR_NOT_SUPPORTED; + ret = ESP_STUB_ERR_NOT_SUPPORTED; } va_end(ap); diff --git a/contrib/loaders/flash/esp/stub_flasher.h b/contrib/loaders/flash/esp/stub_flasher.h index 00714c4243..9e1ed8ce83 100644 --- a/contrib/loaders/flash/esp/stub_flasher.h +++ b/contrib/loaders/flash/esp/stub_flasher.h @@ -1,7 +1,6 @@ /*************************************************************************** * ESP xtensa chips flasher stub definitions * - * Copyright (C) 2017-2019 Espressif Systems Ltd. * - * Author: Alexey Gerenkov * + * Copyright (C) 2017-2021 Espressif Systems Ltd. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -18,48 +17,48 @@ * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ -#ifndef ESP_XTENSA_FLASHER_STUB_H -#define ESP_XTENSA_FLASHER_STUB_H +#ifndef ESP_FLASHER_STUB_H +#define ESP_FLASHER_STUB_H #include -#define ESP_XTENSA_STUB_ERR_OK 0 -#define ESP_XTENSA_STUB_ERR_FAIL (-1) -#define ESP_XTENSA_STUB_ERR_NOT_SUPPORTED (-2) -#define ESP_XTENSA_STUB_ERR_INFLATE (-3) -#define ESP_XTENSA_STUB_ERR_NOT_ENOUGH_DATA (-4) -#define ESP_XTENSA_STUB_ERR_TOO_MUCH_DATA (-5) -#define ESP_XTENSA_STUB_ERR_INVALID_IMAGE (-6) +#define ESP_STUB_ERR_OK 0 +#define ESP_STUB_ERR_FAIL (-1) +#define ESP_STUB_ERR_NOT_SUPPORTED (-2) +#define ESP_STUB_ERR_INFLATE (-3) +#define ESP_STUB_ERR_NOT_ENOUGH_DATA (-4) +#define ESP_STUB_ERR_TOO_MUCH_DATA (-5) +#define ESP_STUB_ERR_INVALID_IMAGE (-6) -#define ESP_XTENSA_STUB_CMD_FLASH_READ 0 -#define ESP_XTENSA_STUB_CMD_FLASH_WRITE 1 -#define ESP_XTENSA_STUB_CMD_FLASH_ERASE 2 -#define ESP_XTENSA_STUB_CMD_FLASH_ERASE_CHECK 3 -#define ESP_XTENSA_STUB_CMD_FLASH_SIZE 4 -#define ESP_XTENSA_STUB_CMD_FLASH_MAP_GET 5 -#define ESP_XTENSA_STUB_CMD_FLASH_BP_SET 6 -#define ESP_XTENSA_STUB_CMD_FLASH_BP_CLEAR 7 -#define ESP_XTENSA_STUB_CMD_FLASH_TEST 8 -#define ESP_XTENSA_STUB_CMD_FLASH_WRITE_DEFLATED 9 -#define ESP_XTENSA_STUB_CMD_FLASH_CALC_HASH 10 -#define ESP_XTENSA_STUB_CMD_CLOCK_CONFIGURE 11 -#define ESP_XTENSA_STUB_CMD_FLASH_MAX_ID ESP_XTENSA_STUB_CMD_CLOCK_CONFIGURE -#define ESP_XTENSA_STUB_CMD_TEST (ESP_XTENSA_STUB_CMD_FLASH_MAX_ID+2) +#define ESP_STUB_CMD_FLASH_READ 0 +#define ESP_STUB_CMD_FLASH_WRITE 1 +#define ESP_STUB_CMD_FLASH_ERASE 2 +#define ESP_STUB_CMD_FLASH_ERASE_CHECK 3 +#define ESP_STUB_CMD_FLASH_SIZE 4 +#define ESP_STUB_CMD_FLASH_MAP_GET 5 +#define ESP_STUB_CMD_FLASH_BP_SET 6 +#define ESP_STUB_CMD_FLASH_BP_CLEAR 7 +#define ESP_STUB_CMD_FLASH_TEST 8 +#define ESP_STUB_CMD_FLASH_WRITE_DEFLATED 9 +#define ESP_STUB_CMD_FLASH_CALC_HASH 10 +#define ESP_STUB_CMD_CLOCK_CONFIGURE 11 +#define ESP_STUB_CMD_FLASH_MAX_ID ESP_STUB_CMD_CLOCK_CONFIGURE +#define ESP_STUB_CMD_TEST (ESP_STUB_CMD_FLASH_MAX_ID+2) -#define ESP_XTENSA_STUB_FLASH_MAPPINGS_MAX_NUM 2 /* IROM, DROM */ +#define ESP_STUB_FLASH_MAPPINGS_MAX_NUM 2 /* IROM, DROM */ -struct esp_xtensa_flash_region_mapping { +struct esp_flash_region_mapping { uint32_t phy_addr; uint32_t load_addr; uint32_t size; }; -struct esp_xtensa_flash_mapping { +struct esp_flash_mapping { uint32_t maps_num; - struct esp_xtensa_flash_region_mapping maps[ESP_XTENSA_STUB_FLASH_MAPPINGS_MAX_NUM]; + struct esp_flash_region_mapping maps[ESP_STUB_FLASH_MAPPINGS_MAX_NUM]; }; -struct esp_xtensa_stub_flash_write_args { +struct esp_flash_stub_flash_write_args { uint32_t start_addr; uint32_t size; uint32_t down_buf_addr; @@ -69,8 +68,8 @@ struct esp_xtensa_stub_flash_write_args { }; /* exported to let openocd know for stack allocation */ -#define ESP_XTENSA_STUB_UNZIP_BUFF_SIZE 32768 -#define ESP_XTENSA_STUB_IFLATOR_SIZE 11000 -#define ESP_XTENSA_STUB_RDWR_BUFF_SIZE 32768 +#define ESP_STUB_UNZIP_BUFF_SIZE 32768 +#define ESP_STUB_IFLATOR_SIZE 11000 +#define ESP_STUB_RDWR_BUFF_SIZE 32768 -#endif /* ESP_XTENSA_FLASHER_STUB_H */ +#endif /* ESP_FLASHER_STUB_H */ diff --git a/contrib/loaders/flash/esp/xtensa/stub_xtensa_chips.h b/contrib/loaders/flash/esp/xtensa/stub_xtensa_chips.h new file mode 100644 index 0000000000..a3868a9ee2 --- /dev/null +++ b/contrib/loaders/flash/esp/xtensa/stub_xtensa_chips.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Xtensa chips common definitions for flasher stub * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ +#ifndef ESP_XTENSA_CHIPS_FLASHER_STUB_H +#define ESP_XTENSA_CHIPS_FLASHER_STUB_H + +#include "eri.h" +#include "trax.h" + +#define ESP_APPTRACE_TRAX_BLOCK_SIZE (0x4000UL) +#define ESP_APPTRACE_USR_DATA_LEN_MAX (ESP_APPTRACE_TRAX_BLOCK_SIZE - 2) + +#define ESP_APPTRACE_TRAX_CTRL_REG ERI_TRAX_DELAYCNT +#define ESP_APPTRACE_TRAX_HOST_CONNECT (1 << 23) + +#define XT_INS_BREAK 0x004000 +#define XT_INS_BREAKN 0xF02D + +#define CPUTICKS2US(_t_) ((_t_)/(stub_esp_clk_cpu_freq()/1000000)) + +inline int stub_apptrace_hw_init(void) +{ + /* imply that host is auto-connected */ + uint32_t reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); + reg |= ESP_APPTRACE_TRAX_HOST_CONNECT; + eri_write(ESP_APPTRACE_TRAX_CTRL_REG, reg); + + return ESP_STUB_ERR_OK; +} + +inline uint64_t stub_get_time(void) +{ + uint32_t ticks = xthal_get_ccount() + return CPUTICKS2US(ticks); +} + +inline int64_t esp_timer_get_time(void) +{ + return (int64_t)stub_get_time(); +} + +static inline uint8_t stub_get_insn_size(uint8_t *insn) +{ + return insn[0] & 0x8 ? 2 : 3; +} + +static inline uint32_t stub_get_break_insn(uint8_t insn_sz) +{ + return insn_sz == 2 ? XT_INS_BREAKN : XT_INS_BREAK; +} + +#endif /*ESP_XTENSA_CHIPS_FLASHER_STUB_H */ diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 3a31b7526e..0aa9cdc03b 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -26,9 +26,12 @@ NOR_DRIVERS = \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ + %D%/esp_flash.c \ %D%/esp_xtensa.c \ + %D%/esp_riscv.c \ %D%/esp32.c \ %D%/esp32s2.c \ + %D%/esp32c3.c \ %D%/esirisc_flash.c \ %D%/faux.c \ %D%/fespi.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 02f46c0a64..dc4c849eeb 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -42,6 +42,7 @@ extern const struct flash_driver em357_flash; extern const struct flash_driver esirisc_flash; extern const struct flash_driver esp32_flash; extern const struct flash_driver esp32s2_flash; +extern const struct flash_driver esp32c3_flash; extern const struct flash_driver faux_flash; extern const struct flash_driver fm3_flash; extern const struct flash_driver fm4_flash; @@ -114,6 +115,7 @@ static const struct flash_driver * const flash_drivers[] = { &esirisc_flash, &esp32_flash, &esp32s2_flash, + &esp32c3_flash, &faux_flash, &fm3_flash, &fm4_flash, diff --git a/src/flash/nor/esp32.c b/src/flash/nor/esp32.c index 03ed85a309..bcd60c641d 100644 --- a/src/flash/nor/esp32.c +++ b/src/flash/nor/esp32.c @@ -43,13 +43,14 @@ static const uint8_t esp32_flasher_stub_data[] = { #include "contrib/loaders/flash/esp/esp32/stub_flasher_data.inc" }; -static struct esp_xtensa_flasher_stub_config s_stub_cfg = { +static const struct esp_flasher_stub_config s_stub_cfg = { .code = esp32_flasher_stub_code, .code_sz = sizeof(esp32_flasher_stub_code), .data = esp32_flasher_stub_data, .data_sz = sizeof(esp32_flasher_stub_data), .entry_addr = ESP32_STUB_ENTRY_ADDR, - .bss_sz = ESP32_STUB_BSS_SIZE + .bss_sz = ESP32_STUB_BSS_SIZE, + .first_user_reg_param = XTENSA_STUB_ARGS_FUNC_START }; @@ -63,7 +64,7 @@ static bool esp32_is_drom_address(target_addr_t addr) return (addr >= ESP32_DROM_LOW && addr < ESP32_DROM_HIGH); } -static const struct esp_xtensa_flasher_stub_config *esp32_get_stub(struct flash_bank *bank) +static const struct esp_flasher_stub_config *esp32_get_stub(struct flash_bank *bank) { return &s_stub_cfg; } @@ -110,13 +111,13 @@ COMMAND_HANDLER(esp32_cmd_appimage_flashoff) struct target *curr; foreach_smp_target(head, target->head) { curr = head->target; - int ret = CALL_COMMAND_HANDLER(esp_xtensa_cmd_appimage_flashoff_do, curr); + int ret = CALL_COMMAND_HANDLER(esp_flash_cmd_appimage_flashoff_do, curr); if (ret != ERROR_OK) return ret; } return ERROR_OK; } - return CALL_COMMAND_HANDLER(esp_xtensa_cmd_appimage_flashoff_do, target); + return CALL_COMMAND_HANDLER(esp_flash_cmd_appimage_flashoff_do, target); } COMMAND_HANDLER(esp32_cmd_compression) @@ -128,24 +129,24 @@ COMMAND_HANDLER(esp32_cmd_compression) struct target *curr; foreach_smp_target(head, target->head) { curr = head->target; - int ret = CALL_COMMAND_HANDLER(esp_xtensa_cmd_set_compression, curr); + int ret = CALL_COMMAND_HANDLER(esp_flash_cmd_set_compression, curr); if (ret != ERROR_OK) return ret; } return ERROR_OK; } - return CALL_COMMAND_HANDLER(esp_xtensa_cmd_set_compression, target); + return CALL_COMMAND_HANDLER(esp_flash_cmd_set_compression, target); } COMMAND_HANDLER(esp32_cmd_verify_bank_hash) { - return CALL_COMMAND_HANDLER(esp_xtensa_parse_cmd_verify_bank_hash, + return CALL_COMMAND_HANDLER(esp_flash_parse_cmd_verify_bank_hash, get_current_target(CMD_CTX)); } COMMAND_HANDLER(esp32_cmd_set_clock) { - return CALL_COMMAND_HANDLER(esp_xtensa_parse_cmd_clock_boost, + return CALL_COMMAND_HANDLER(esp_flash_parse_cmd_clock_boost, get_current_target(CMD_CTX)); } @@ -224,14 +225,14 @@ struct flash_driver esp32_flash = { .name = "esp32", .commands = esp32_all_command_handlers, .flash_bank_command = esp32_flash_bank_command, - .erase = esp_xtensa_erase, - .protect = esp_xtensa_protect, - .write = esp_xtensa_write, - .read = esp_xtensa_read, - .probe = esp_xtensa_probe, - .auto_probe = esp_xtensa_auto_probe, - .erase_check = esp_xtensa_blank_check, - .protect_check = esp_xtensa_protect_check, + .erase = esp_flash_erase, + .protect = esp_flash_protect, + .write = esp_flash_write, + .read = esp_flash_read, + .probe = esp_flash_probe, + .auto_probe = esp_flash_auto_probe, + .erase_check = esp_flash_blank_check, + .protect_check = esp_flash_protect_check, .info = esp32_get_info, .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/esp32c3.c b/src/flash/nor/esp32c3.c new file mode 100644 index 0000000000..0c443cefe6 --- /dev/null +++ b/src/flash/nor/esp32c3.c @@ -0,0 +1,130 @@ +/*************************************************************************** + * ESP32-C3 flash driver for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "imp.h" +#include "esp_riscv.h" +#include "contrib/loaders/flash/esp/esp32c3/stub_flasher_image.h" +#include "contrib/loaders/flash/esp/esp32c3/sdkconfig.h" + +#define ESP32C3_FLASH_SECTOR_SIZE 4096 + +struct esp32c3_flash_bank { + struct esp_riscv_flash_bank riscv; +}; + +static const uint8_t s_esp32c3_flasher_stub_code[] = { +#include "contrib/loaders/flash/esp/esp32c3/stub_flasher_code.inc" +}; +static const uint8_t s_esp32c3_flasher_stub_data[] = { +#include "contrib/loaders/flash/esp/esp32c3/stub_flasher_data.inc" +}; + +static const struct esp_flasher_stub_config s_esp32c3_stub_cfg = { + .code = s_esp32c3_flasher_stub_code, + .code_sz = sizeof(s_esp32c3_flasher_stub_code), + .data = s_esp32c3_flasher_stub_data, + .data_sz = sizeof(s_esp32c3_flasher_stub_data), + .entry_addr = ESP32C3_STUB_ENTRY_ADDR, + .bss_sz = ESP32C3_STUB_BSS_SIZE, + .first_user_reg_param = RISCV_STUB_ARGS_FUNC_START, + .apptrace_ctrl_addr = ESP32C3_STUB_APPTRACE_CTRL_ADDR, + .stack_data_pool_sz = CONFIG_STUB_STACK_DATA_POOL_SIZE +}; + +static bool esp32c3_is_irom_address(target_addr_t addr) +{ + return (addr >= ESP32C3_IROM_LOW && addr < ESP32C3_IROM_HIGH); +} + +static bool esp32c3_is_drom_address(target_addr_t addr) +{ + return (addr >= ESP32C3_DROM_LOW && addr < ESP32C3_DROM_HIGH); +} + +static const struct esp_flasher_stub_config *esp32c3_get_stub(struct flash_bank *bank) +{ + return &s_esp32c3_stub_cfg; +} + +/* flash bank esp32 0 0 + If is zero flash size will be autodetected, otherwise user value will be used + */ +FLASH_BANK_COMMAND_HANDLER(esp32c3_flash_bank_command) +{ + struct esp32c3_flash_bank *esp32c3_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + esp32c3_info = malloc(sizeof(struct esp32c3_flash_bank)); + if (esp32c3_info == NULL) + return ERROR_FAIL; + int ret = esp_riscv_flash_init(&esp32c3_info->riscv, + ESP32C3_FLASH_SECTOR_SIZE, + algorithm_run_func_image, + esp32c3_is_irom_address, + esp32c3_is_drom_address, + esp32c3_get_stub); + if (ret != ERROR_OK) { + free(esp32c3_info); + return ret; + } + bank->driver_priv = esp32c3_info; + return ERROR_OK; +} + +static int esp32c3_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + snprintf(buf, buf_size, "ESP32C3"); + return ERROR_OK; +} + +static const struct command_registration esp32c3_command_handlers[] = { + { + .name = "esp", + .mode = COMMAND_ANY, + .help = "ESP flash command group", + .usage = "", + .chain = esp_flash_exec_flash_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver esp32c3_flash = { + .name = "esp32c3", + .commands = esp32c3_command_handlers, + .flash_bank_command = esp32c3_flash_bank_command, + .erase = esp_flash_erase, + .protect = esp_flash_protect, + .write = esp_flash_write, + .read = esp_flash_read, + .probe = esp_flash_probe, + .auto_probe = esp_flash_auto_probe, + .erase_check = esp_flash_blank_check, + .protect_check = esp_flash_protect_check, + .info = esp32c3_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/esp32s2.c b/src/flash/nor/esp32s2.c index 5400dc76c5..f0cc58fdd7 100644 --- a/src/flash/nor/esp32s2.c +++ b/src/flash/nor/esp32s2.c @@ -24,6 +24,7 @@ #endif #include "imp.h" +#include #include #include #include @@ -43,13 +44,14 @@ static const uint8_t esp32s2_flasher_stub_data[] = { #include "contrib/loaders/flash/esp/esp32_s2/stub_flasher_data.inc" }; -static struct esp_xtensa_flasher_stub_config s_esp32s2_stub_cfg = { +static struct esp_flasher_stub_config s_esp32s2_stub_cfg = { .code = esp32s2_flasher_stub_code, .code_sz = sizeof(esp32s2_flasher_stub_code), .data = esp32s2_flasher_stub_data, .data_sz = sizeof(esp32s2_flasher_stub_data), .entry_addr = ESP32_S2_STUB_ENTRY_ADDR, - .bss_sz = ESP32_S2_STUB_BSS_SIZE + .bss_sz = ESP32_S2_STUB_BSS_SIZE, + .first_user_reg_param = XTENSA_STUB_ARGS_FUNC_START }; static bool esp32s2_is_irom_address(target_addr_t addr) @@ -62,7 +64,7 @@ static bool esp32s2_is_drom_address(target_addr_t addr) return (addr >= ESP32_S2_DROM_LOW && addr < ESP32_S2_DROM_HIGH); } -static const struct esp_xtensa_flasher_stub_config *esp32s2_get_stub(struct flash_bank *bank) +static const struct esp_flasher_stub_config *esp32s2_get_stub(struct flash_bank *bank) { struct esp32s2_common *esp32 = target_to_esp32s2(bank->target); @@ -89,7 +91,7 @@ FLASH_BANK_COMMAND_HANDLER(esp32s2_flash_bank_command) return ERROR_FAIL; int ret = esp_xtensa_flash_init(&esp32s2_info->esp_xtensa, ESP32_S2_FLASH_SECTOR_SIZE, - xtensa_run_func_image, + algorithm_run_func_image, esp32s2_is_irom_address, esp32s2_is_drom_address, esp32s2_get_stub); @@ -113,7 +115,7 @@ static const struct command_registration esp32s2_command_handlers[] = { .mode = COMMAND_ANY, .help = "ESP flash command group", .usage = "", - .chain = esp_xtensa_exec_flash_command_handlers, + .chain = esp_flash_exec_flash_command_handlers, }, COMMAND_REGISTRATION_DONE }; @@ -122,14 +124,14 @@ struct flash_driver esp32s2_flash = { .name = "esp32s2", .commands = esp32s2_command_handlers, .flash_bank_command = esp32s2_flash_bank_command, - .erase = esp_xtensa_erase, - .protect = esp_xtensa_protect, - .write = esp_xtensa_write, - .read = esp_xtensa_read, - .probe = esp_xtensa_probe, - .auto_probe = esp_xtensa_auto_probe, - .erase_check = esp_xtensa_blank_check, - .protect_check = esp_xtensa_protect_check, + .erase = esp_flash_erase, + .protect = esp_flash_protect, + .write = esp_flash_write, + .read = esp_flash_read, + .probe = esp_flash_probe, + .auto_probe = esp_flash_auto_probe, + .erase_check = esp_flash_blank_check, + .protect_check = esp_flash_protect_check, .info = esp32s2_get_info, .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/esp_flash.c b/src/flash/nor/esp_flash.c new file mode 100644 index 0000000000..0f6ca49009 --- /dev/null +++ b/src/flash/nor/esp_flash.c @@ -0,0 +1,1558 @@ +/*************************************************************************** + * Generic flash driver for Espressif chips * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* + * Overview + * -------- + * Like many other flash drivers this one uses special binary program (stub) running on target + * to perform all operations and communicate to the host. Stub has entry function which accepts + * variable number of arguments and therefore can handle different flash operation requests. + * Only the first argument of the stub entry function is mandatory for all operations it must + * specify the type of flash function to perform (read, write etc.). Actually stub main function + * is a dispatcher which determines the type of flash operation to perform, retrieves other + * arguments and calls corresponding handler. In C notation entry function looks like the following: + + * int stub_main(int cmd, ...); + + * In general every flash operation consists of the following steps: + * 1) Stub is loaded to target. + * 2) Necessary arguments are prepared and stub's main function is called. + * 3) Stub does the work and returns the result. + + * Stub Loading + * ------------ + * To run stub its code and data sections must be loaded to the target. It is done using working area API. + * But since code and data address spaces are separated in ESP32 it is necessary to have two configured + * working areas: one in code address space and another one in data space. So driver allocates chunks + * in respective pools and writes stub sections to them. It is important that the both stub sections reside + * at the beginning of respective working areas because stub code is linked as ELF and therefore it is + * position dependent. So target memory for stub code and data must be allocated first. + + * Stub Execution + * -------------- + * Special wrapping code is used to enter and exit the stub's main function. It prepares register arguments + * before Windowed ABI call to stub entry and upon return from it executes break command to indicate to OpenOCD + * that operation is finished. + + * Flash Data Transfers + * -------------------- + * To transfer data from/to target a buffer should be allocated at ESP32 side. Also during the data transfer + * target and host must maintain the state of that buffer (read/write pointers etc.). So host needs to check + * the state of that buffer periodically and write to or read from it (depending on flash operation type). + * ESP32 does not support access to its memory via JTAG when it is not halted, so accessing target memory would + * requires halting the CPUs every time the host needs to check if there are incoming data or free space available + * in the buffer. This fact can slow down flash write/read operations dramatically. To avoid this flash driver and + * stub use application level tracing module API to transfer the data in 'non-stop' mode. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include +#include "time_support.h" +#include "contrib/loaders/flash/esp/stub_flasher.h" +#include "esp_flash.h" +#include "time_support.h" + +#include + +#define ESP_FLASH_RW_TMO 20000 /* ms */ +#define ESP_FLASH_ERASE_TMO 60000 /* ms */ + +struct esp_flash_rw_args { + int (*xfer)(struct target *target, uint32_t block_id, uint32_t len, void *priv); + uint8_t *buffer; + uint32_t count; + uint32_t total_count; + bool connected; + const struct esp_flash_apptrace_hw *apptrace; + target_addr_t apptrace_ctrl_addr; +}; + +struct esp_flash_write_state { + struct esp_flash_rw_args rw; + uint32_t prev_block_id; + struct working_area *target_buf; + struct working_area *stub_wargs_area; + struct esp_flash_stub_flash_write_args stub_wargs; +}; + +struct esp_flash_read_state { + struct esp_flash_rw_args rw; + uint8_t *rd_buf; +}; + +struct esp_flash_erase_check_args { + struct working_area *erased_state_buf; + uint32_t num_sectors; +}; + +struct esp_flash_bp_op_state { + struct working_area *target_buf; + struct esp_flash_bank *esp_info; +}; + +static int esp_flash_compress(const uint8_t *in, uint32_t in_len, uint8_t **out, uint32_t *out_len) +{ + z_stream strm; + int wbits = -MAX_WBITS; /*deflate */ + int level = Z_DEFAULT_COMPRESSION; /*Z_BEST_SPEED; */ + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + if (deflateInit2(&strm, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, + Z_DEFAULT_STRATEGY) != Z_OK) { + LOG_ERROR("deflateInit2 error!"); + return ERROR_FAIL; + } + + strm.avail_out = deflateBound(&strm, (uLong)in_len); + + /* Some compression methods may need a little more space */ + strm.avail_out += 100; + + if (strm.avail_out > INT_MAX) { + deflateEnd(&strm); + return ERROR_FAIL; + } + + *out = (uint8_t *)malloc((int)strm.avail_out); + if (*out == NULL) { + LOG_ERROR("out buffer allocation failed!"); + return ERROR_FAIL; + } + strm.next_out = *out; + strm.next_in = (uint8_t *)in; + strm.avail_in = (uInt)in_len; + + /* always compress in one pass - the return value holds the entire + * decompressed data anyway, so there's no reason to do chunked + * decompression */ + if (deflate(&strm, Z_FINISH) != Z_STREAM_END) { + free(*out); + deflateEnd(&strm); + LOG_ERROR("not enough output space"); + return ERROR_FAIL; + } + + deflateEnd(&strm); + + if (strm.total_out > INT_MAX) { + free(*out); + LOG_ERROR("too much output"); + return ERROR_FAIL; + } + + *out_len = strm.total_out; + + LOG_DEBUG("inlen:(%u) outlen:(%u)!", in_len, *out_len); + + return ERROR_OK; +} + +static int esp_calc_hash(const uint8_t *data, size_t datalen, uint8_t *hash) +{ + if (data == NULL || hash == NULL || datalen == 0) + return ERROR_FAIL; + + struct tc_sha256_state_struct sha256_state; + + if (tc_sha256_init(&sha256_state) != TC_CRYPTO_SUCCESS) { + LOG_ERROR("tc_sha256_init failed!"); + return ERROR_FAIL; + } + + if (tc_sha256_update(&sha256_state, data, datalen) != TC_CRYPTO_SUCCESS) { + LOG_ERROR("tc_sha256_update failed!"); + return ERROR_FAIL; + } + + if (tc_sha256_final(hash, &sha256_state) != TC_CRYPTO_SUCCESS) { + LOG_ERROR("tc_sha256_final failed!"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int esp_flasher_algorithm_init(struct algorithm_run_data *algo, + const struct algorithm_hw *stub_hw, + const struct esp_flasher_stub_config *stub_cfg) +{ + if (!stub_cfg) { + LOG_ERROR("Invalid stub!"); + return ERROR_FAIL; + } + + memset(algo, 0, sizeof(*algo)); + algo->hw = stub_hw; + algo->reg_args.first_user_param = stub_cfg->first_user_reg_param; + algo->image.bss_size = stub_cfg->bss_sz; + memset(&algo->image.image, 0, sizeof(algo->image.image)); + int ret = image_open(&algo->image.image, NULL, "build"); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to create image (%d)!", ret); + return ret; + } + algo->image.image.start_address_set = 1; + algo->image.image.start_address = stub_cfg->entry_addr; + ret = image_add_section(&algo->image.image, + 0, + stub_cfg->code_sz, + IMAGE_ELF_PHF_EXEC, + stub_cfg->code); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to create image (%d)!", ret); + image_close(&algo->image.image); + return ret; + } + ret = image_add_section(&algo->image.image, 0, stub_cfg->data_sz, 0, stub_cfg->data); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to create image (%d)!", ret); + image_close(&algo->image.image); + return ret; + } + LOG_DEBUG("base=%08x set=%d", + (unsigned) algo->image.image.base_address, + algo->image.image.base_address_set); + return ret; +} + +int esp_flash_init(struct esp_flash_bank *esp_info, uint32_t sec_sz, + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...), + bool (*is_irom_address)(target_addr_t addr), + bool (*is_drom_address)(target_addr_t addr), + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank), + const struct esp_flash_apptrace_hw *apptrace_hw, + const struct algorithm_hw *stub_hw) +{ + + esp_info->probed = 0; + esp_info->sec_sz = sec_sz; + esp_info->get_stub = get_stub; + esp_info->run_func_image = run_func_image; + esp_info->is_irom_address = is_irom_address; + esp_info->is_drom_address = is_drom_address; + esp_info->hw_flash_base = 0; + esp_info->appimage_flash_base = (uint32_t)-1; + esp_info->compression = 1; /* enables compression by default */ + esp_info->apptrace_hw = apptrace_hw; + esp_info->stub_hw = stub_hw; + + return ERROR_OK; +} + +int esp_flash_protect(struct flash_bank *bank, int set, int first, int last) +{ + return ERROR_FAIL; +} + +int esp_flash_protect_check(struct flash_bank *bank) +{ + return ERROR_OK; +} + +int esp_flash_blank_check(struct flash_bank *bank) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted!"); + return ERROR_TARGET_NOT_HALTED; + } + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + run.stack_size = 1300; + struct mem_param mp; + init_mem_param(&mp, 3 /*3rd usr arg*/, bank->num_sectors /*size in bytes*/, PARAM_IN); + run.mem_args.params = ∓ + run.mem_args.count = 1; + + ret = esp_info->run_func_image(bank->target, + &run, + 4, + ESP_STUB_CMD_FLASH_ERASE_CHECK /*cmd*/, + esp_info->hw_flash_base/esp_info->sec_sz /*start*/, + bank->num_sectors /*sectors num*/, + 0 /*address to store sectors' state*/); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + destroy_mem_param(&mp); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to check erase flash (%" PRId64 ")!", run.ret_code); + ret = ERROR_FAIL; + } else { + for (int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = mp.value[i]; + } + destroy_mem_param(&mp); + return ret; +} + +static uint32_t esp_flash_get_size(struct flash_bank *bank) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + uint32_t size = 0; + struct algorithm_run_data run; + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + run.stack_size = 1024; + ret = esp_info->run_func_image(bank->target, + &run, + 1, + ESP_STUB_CMD_FLASH_SIZE); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + return 0; + } + size = (uint32_t)run.ret_code; + if (size == 0) + LOG_ERROR("Failed to get flash size!"); + LOG_DEBUG("%s size 0x%x", __func__, size); + return size; +} + +static int esp_flash_get_mappings(struct flash_bank *bank, + struct esp_flash_bank *esp_info, + struct esp_flash_mapping *flash_map, + uint32_t appimage_flash_base) +{ + struct algorithm_run_data run; + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + run.stack_size = 1300; + + struct mem_param mp; + init_mem_param(&mp, + 2 /*2nd usr arg*/, + sizeof(struct esp_flash_mapping) /*size in bytes*/, + PARAM_IN); + run.mem_args.params = ∓ + run.mem_args.count = 1; + + ret = esp_info->run_func_image(bank->target, + &run, + 3 /*args num*/, + ESP_STUB_CMD_FLASH_MAP_GET /*cmd*/, + appimage_flash_base, + 0 /*address to store mappings*/); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + destroy_mem_param(&mp); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to get flash maps (%" PRId64 ")!", run.ret_code); + if (run.ret_code == ESP_STUB_ERR_INVALID_IMAGE) + LOG_WARNING( + "Application image is invalid! Check configured binary flash offset 'appimage_offset'."); + ret = ERROR_FAIL; + } else { + memcpy(flash_map, mp.value, sizeof(struct esp_flash_mapping)); + if (flash_map->maps_num == 0) + LOG_WARNING("Empty flash mapping!"); + for (uint32_t i = 0; i < flash_map->maps_num; i++) + LOG_INFO("Flash mapping %d: 0x%x -> 0x%x, %d KB", + i, + flash_map->maps[i].phy_addr, + flash_map->maps[i].load_addr, + flash_map->maps[i].size/1024); + } + destroy_mem_param(&mp); + return ret; +} + +int esp_flash_erase(struct flash_bank *bank, int first, int last) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + assert((0 <= first) && (first <= last) && (last < bank->num_sectors)); + if (esp_info->hw_flash_base + first*esp_info->sec_sz < + esp_info->flash_min_offset) { + LOG_ERROR("Invalid offset!"); + return ERROR_FAIL; + } + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + run.stack_size = 1024; + run.tmo = ESP_FLASH_ERASE_TMO; + ret = esp_info->run_func_image(bank->target, + &run, + 3, + ESP_STUB_CMD_FLASH_ERASE, + /* cmd */ + esp_info->hw_flash_base + first*esp_info->sec_sz, + /* start addr */ + (last-first+1)*esp_info->sec_sz); /* size */ + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to erase flash (%" PRId64 ")!", run.ret_code); + ret = ERROR_FAIL; + } + return ret; +} + +static int esp_flash_rw_do(struct target *target, void *priv) +{ + struct duration algo_time, tmo_time; + struct esp_flash_rw_args *rw = (struct esp_flash_rw_args *)priv; + int retval = ERROR_OK, busy_num = 0; + + if (duration_start(&algo_time) != 0) { + LOG_ERROR("Failed to start data write time measurement!"); + return ERROR_FAIL; + } + while (rw->total_count < rw->count) { + uint32_t block_id = 0, len = 0; + LOG_DEBUG("Transfer block on %s", target_name(target)); + retval = rw->apptrace->data_len_read(target, &block_id, &len); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read apptrace status (%d)!", retval); + return retval; + } + /* transfer block */ + LOG_DEBUG("Transfer block %d, %d bytes", block_id, len); + retval = rw->xfer(target, block_id, len, rw); + if (retval == ERROR_WAIT) { + LOG_DEBUG("Block not ready"); + if (busy_num++ == 0) { + if (duration_start(&tmo_time) != 0) { + LOG_ERROR("Failed to start data write time measurement!"); + return ERROR_FAIL; + } + } else { + /* if no transfer check tmo */ + if (duration_measure(&tmo_time) != 0) { + LOG_ERROR("Failed to stop algo run measurement!"); + return ERROR_FAIL; + } + if (1000*duration_elapsed(&tmo_time) > ESP_FLASH_RW_TMO) { + LOG_ERROR("Transfer data tmo!"); + return ERROR_WAIT; + } + } + } else if (retval != ERROR_OK) { + LOG_ERROR("Failed to transfer flash data block (%d)!", retval); + return retval; + } else + busy_num = 0; + alive_sleep(10); + if (target->state != TARGET_DEBUG_RUNNING) { + LOG_ERROR("Algorithm accidentally stopped (%d)!", target->state); + return ERROR_FAIL; + } + } + if (duration_measure(&algo_time) != 0) { + LOG_ERROR("Failed to stop data write measurement!"); + return ERROR_FAIL; + } + LOG_INFO("PROF: Data transferred in %g ms @ %g KB/s", + duration_elapsed(&algo_time)*1000, + duration_kbps(&algo_time, rw->total_count)); + + return ERROR_OK; +} + +static int esp_flash_write_xfer(struct target *target, uint32_t block_id, uint32_t len, void *priv) +{ + struct esp_flash_write_state *state = (struct esp_flash_write_state *)priv; + int retval; + + /* check for target to get connected */ + if (!state->rw.connected) { + retval = + state->rw.apptrace->ctrl_reg_read(target, NULL, NULL, &state->rw.connected); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read apptrace control reg (%d)!", retval); + return retval; + } + if (!state->rw.connected) + return ERROR_WAIT; + /* got connected, apptrace is initied on target, call `info_init` once more to + * update control block info */ + if (state->rw.apptrace->info_init) { + retval = state->rw.apptrace->info_init(target, + state->rw.apptrace_ctrl_addr, + NULL); + if (retval != ERROR_OK) + return retval; + } + } + + if (state->prev_block_id == block_id) + return ERROR_WAIT; + + uint32_t wr_sz = state->rw.count - state->rw.total_count < + state->rw.apptrace->usr_block_max_size_get(target) ? + state->rw.count - + state->rw.total_count : state->rw.apptrace->usr_block_max_size_get(target); + retval = state->rw.apptrace->usr_block_write(target, + block_id, + state->rw.buffer + state->rw.total_count, + wr_sz); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write apptrace data (%d)!", retval); + return retval; + } + state->rw.total_count += wr_sz; + state->prev_block_id = block_id; + + return ERROR_OK; +} + +static int esp_flash_write_state_init(struct target *target, + struct algorithm_run_data *run, + struct esp_flash_write_state *state) +{ + struct duration algo_time; + + /* clear control register, stub will set APPTRACE_HOST_CONNECT bit when it will be + * ready */ + int ret = state->rw.apptrace->ctrl_reg_write(target, + 0 /*block_id*/, + 0 /*len*/, + false /*conn*/, + false /*data*/); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to clear apptrace ctrl reg (%d)!", ret); + return ret; + } + + /* alloc memory for stub flash write arguments in data working area */ + if (target_alloc_alt_working_area(target, sizeof(state->stub_wargs), + &state->stub_wargs_area) != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc space for stub flash arguments"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* memory buffer */ + if (duration_start(&algo_time) != 0) { + LOG_ERROR("Failed to start workarea alloc time measurement!"); + return ERROR_FAIL; + } + uint32_t buffer_size = 64*1024; + while (target_alloc_alt_working_area_try(target, buffer_size, + &state->target_buf) != ERROR_OK) { + buffer_size /= 2; + if (buffer_size == 0) { + LOG_ERROR("Failed to alloc target buffer for flash data!"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + if (duration_measure(&algo_time) != 0) { + LOG_ERROR("Failed to stop workarea alloc measurement!"); + return ERROR_FAIL; + } + LOG_DEBUG("PROF: Allocated target buffer %d bytes in %g ms", + buffer_size, + duration_elapsed(&algo_time)*1000); + + state->stub_wargs.down_buf_addr = state->target_buf->address; + state->stub_wargs.down_buf_size = state->target_buf->size; + + ret = target_write_buffer(target, state->stub_wargs_area->address, + sizeof(state->stub_wargs), (uint8_t *)&state->stub_wargs); + if (ret != ERROR_OK) { + LOG_ERROR("Write memory at address " TARGET_ADDR_FMT " failed", + state->stub_wargs_area->address); + return ERROR_TARGET_FAILURE; + } + + algorithm_user_arg_set_uint(run, 1, state->stub_wargs_area->address); + + return ERROR_OK; +} + +static void esp_flash_write_state_cleanup(struct target *target, + struct algorithm_run_data *run, + struct esp_flash_write_state *state) +{ + struct duration algo_time; + + if (!state->target_buf) + return; + if (duration_start(&algo_time) != 0) + LOG_ERROR("Failed to start workarea alloc time measurement!"); + target_free_alt_working_area(target, state->target_buf); + target_free_alt_working_area(target, state->stub_wargs_area); + if (duration_measure(&algo_time) != 0) + LOG_ERROR("Failed to stop data write measurement!"); + LOG_DEBUG("PROF: Workarea freed in %g ms", duration_elapsed(&algo_time)*1000); +} + +int esp_flash_apptrace_info_init(struct target *target, struct esp_flash_bank *esp_info, + target_addr_t new_addr, target_addr_t *old_addr) +{ + if (esp_info->apptrace_hw->info_init) + return esp_info->apptrace_hw->info_init(target, new_addr, old_addr); + *old_addr = 0; + return ERROR_OK; +} + +int esp_flash_apptrace_info_restore(struct target *target, + struct esp_flash_bank *esp_info, + target_addr_t old_addr) +{ + if (esp_info->apptrace_hw->info_init) + return esp_info->apptrace_hw->info_init(target, old_addr, NULL); + return ERROR_OK; +} + +int esp_flash_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + struct esp_flash_write_state wr_state; + const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank); + uint8_t *compressed_buff = NULL; + uint32_t compressed_len = 0; + uint32_t stack_size = 1024 + ESP_STUB_UNZIP_BUFF_SIZE; + + if (esp_info->hw_flash_base + offset < esp_info->flash_min_offset) { + LOG_ERROR("Invalid offset!"); + return ERROR_FAIL; + } + if (offset & 0x3UL) { + LOG_ERROR("Unaligned offset!"); + return ERROR_FAIL; + } + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + target_addr_t old_addr = 0; + /* apptrace is not running on target, so not all fields are inited. */ + /* Now we just set control struct addr to be able to communicate and detect that apptrace is + * inited */ + /* TODO: for m-core chip stub_cfg->apptrace_ctrl_addr is array address of control structs + * for all cores */ + int ret = esp_flash_apptrace_info_init(bank->target, + esp_info, + stub_cfg->apptrace_ctrl_addr, + &old_addr); + if (ret != ERROR_OK) + return ret; + + ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg); + if (ret != ERROR_OK) { + esp_flash_apptrace_info_restore(bank->target, esp_info, old_addr); + return ret; + } + + if (esp_info->compression) { + struct duration bench; + duration_start(&bench); + if (esp_flash_compress(buffer, count, &compressed_buff, + &compressed_len) != ERROR_OK) { + LOG_ERROR("Compression failed!"); + return ERROR_FAIL; + } + duration_measure(&bench); + LOG_INFO("Compressed %" PRIu32 " bytes to %" PRIu32 " bytes " + "in %fs", + count, + compressed_len, + duration_elapsed(&bench)); + + stack_size += ESP_STUB_IFLATOR_SIZE; + } + + run.stack_size = stack_size + stub_cfg->stack_data_pool_sz; + run.usr_func = esp_flash_rw_do; + run.usr_func_arg = &wr_state; + run.usr_func_init = (algorithm_usr_func_init_t)esp_flash_write_state_init; + run.usr_func_done = (algorithm_usr_func_done_t)esp_flash_write_state_cleanup; + memset(&wr_state, 0, sizeof(struct esp_flash_write_state)); + wr_state.rw.buffer = esp_info->compression ? compressed_buff : (uint8_t *)buffer; + wr_state.rw.count = esp_info->compression ? compressed_len : count; + wr_state.rw.xfer = esp_flash_write_xfer; + wr_state.rw.apptrace = esp_info->apptrace_hw; + wr_state.prev_block_id = (uint32_t)-1; + wr_state.rw.apptrace_ctrl_addr = stub_cfg->apptrace_ctrl_addr; + /* stub flasher arguments */ + wr_state.stub_wargs.size = wr_state.rw.count; + wr_state.stub_wargs.total_size = count; + wr_state.stub_wargs.start_addr = esp_info->hw_flash_base + offset; + wr_state.stub_wargs.down_buf_addr = 0; + wr_state.stub_wargs.down_buf_size = 0; + + ret = esp_info->run_func_image(bank->target, + &run, + 2, + esp_info->compression ? ESP_STUB_CMD_FLASH_WRITE_DEFLATED : + ESP_STUB_CMD_FLASH_WRITE, + /* cmd */ + 0 + /* esp_stub_flash_write_args */); + if (compressed_buff) + free(compressed_buff); + esp_flash_apptrace_info_restore(bank->target, esp_info, old_addr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to write flash (%" PRId64 ")!", run.ret_code); + ret = ERROR_FAIL; + } + return ret; +} + +static int esp_flash_read_xfer(struct target *target, uint32_t block_id, uint32_t len, void *priv) +{ + struct esp_flash_read_state *state = (struct esp_flash_read_state *)priv; + int retval; + + /* check for target to get connected */ + if (!state->rw.connected) { + retval = + state->rw.apptrace->ctrl_reg_read(target, NULL, NULL, &state->rw.connected); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read apptrace control reg (%d)!", retval); + return retval; + } + if (!state->rw.connected) + return ERROR_WAIT; + /* got connected, apptrace is initied on target, call `info_init` once more to + * update control block info */ + if (state->rw.apptrace->info_init) { + retval = state->rw.apptrace->info_init(target, + state->rw.apptrace_ctrl_addr, + NULL); + if (retval != ERROR_OK) + return retval; + } + state->rd_buf = malloc(state->rw.apptrace->block_max_size_get(target)); + if (!state->rd_buf) { + LOG_ERROR("Failed to alloc read buffer!"); + return ERROR_FAIL; + } + } + + if (len == 0) + return ERROR_WAIT; + + retval = state->rw.apptrace->data_read(target, len, state->rd_buf, block_id, 1 /*ack*/); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read apptrace status (%d)!", retval); + return retval; + } + LOG_DEBUG("DATA %d bytes: %x %x %x %x %x %x %x %x", len, + state->rd_buf[0], state->rd_buf[1], state->rd_buf[2], state->rd_buf[3], + state->rd_buf[4], state->rd_buf[5], state->rd_buf[6], state->rd_buf[7]); + + uint8_t *ptr = state->rd_buf; + while (ptr < state->rd_buf + len) { + uint32_t data_sz = 0; + ptr = state->rw.apptrace->usr_block_get(ptr, &data_sz); + if (data_sz > 0) + memcpy(state->rw.buffer + state->rw.total_count, ptr, data_sz); + ptr += data_sz; + state->rw.total_count += data_sz; + } + + return ERROR_OK; +} + +static int esp_flash_read_state_init(struct target *target, + struct algorithm_run_data *run, + struct esp_flash_read_state *state) +{ + /* clear control register, stub will set APPTRACE_HOST_CONNECT bit when it will be + * ready */ + int ret = state->rw.apptrace->ctrl_reg_write(target, + 0 /*block_id*/, + 0 /*len*/, + false /*conn*/, + false /*data*/); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to clear apptrace ctrl reg (%d)!", ret); + return ret; + } + return ERROR_OK; +} + +int esp_flash_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + struct esp_flash_read_state rd_state; + const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank); + + if (offset & 0x3UL) { + LOG_ERROR("Unaligned offset!"); + return ERROR_FAIL; + } + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + target_addr_t old_addr = 0; + /* apptrace is not running on target, so not all fields are inited. */ + /* Now we just set control struct addr to be able to communicate and detect that apptrace is + * inited */ + /* TODO: for m-core chip stub_cfg->apptrace_ctrl_addr is array address of control structs + * for all cores */ + int ret = esp_flash_apptrace_info_init(bank->target, + esp_info, + stub_cfg->apptrace_ctrl_addr, + &old_addr); + if (ret != ERROR_OK) + return ret; + + ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg); + if (ret != ERROR_OK) { + esp_flash_apptrace_info_restore(bank->target, esp_info, old_addr); + return ret; + } + + run.stack_size = 1024 + stub_cfg->stack_data_pool_sz; + run.usr_func_init = (algorithm_usr_func_init_t)esp_flash_read_state_init; + run.usr_func = esp_flash_rw_do; + run.usr_func_arg = &rd_state; + memset(&rd_state, 0, sizeof(struct esp_flash_read_state)); + rd_state.rw.buffer = buffer; + rd_state.rw.count = count; + rd_state.rw.xfer = esp_flash_read_xfer; + rd_state.rw.apptrace = esp_info->apptrace_hw; + rd_state.rw.apptrace_ctrl_addr = stub_cfg->apptrace_ctrl_addr; + + ret = esp_info->run_func_image(bank->target, + &run, + 3, + /* cmd */ + ESP_STUB_CMD_FLASH_READ, + /* start addr */ + esp_info->hw_flash_base + offset, + /* size */ + count); + + free(rd_state.rd_buf); + esp_flash_apptrace_info_restore(bank->target, esp_info, old_addr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to read flash (%" PRId64 ")!", run.ret_code); + ret = ERROR_FAIL; + } + return ret; +} + +#define BANK_SUBNAME(_b_, _n_) (strcmp((_b_)->name + strlen((_b_)->name) - strlen(_n_), _n_) == 0) + +int esp_flash_probe(struct flash_bank *bank) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct esp_flash_mapping flash_map = {.maps_num = 0}; + uint32_t irom_base = 0, irom_sz = 0, drom_base = 0, drom_sz = 0, irom_flash_base = 0, + drom_flash_base = 0; + + esp_info->probed = 0; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + LOG_DEBUG("Flash size = %d KB @ "TARGET_ADDR_FMT " '%s' - '%s'", + bank->size/1024, + bank->base, + target_name(bank->target), + target_state_name(bank->target)); + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + int ret = esp_flash_get_mappings(bank, + esp_info, + &flash_map, + esp_info->appimage_flash_base); + if (ret != ERROR_OK || flash_map.maps_num == 0) { + LOG_WARNING("Failed to get flash mappings (%d)!", ret); + /* if no DROM/IROM mappings so pretend they are at the end of the HW flash bank and + * have zero size to allow correct memory map with non zero RAM region */ + irom_base = drom_base = esp_flash_get_size(bank); + } else { + for (uint32_t i = 0; i < flash_map.maps_num; i++) { + if (esp_info->is_irom_address(flash_map.maps[i].load_addr)) { + irom_flash_base = flash_map.maps[i].phy_addr & + ~(esp_info->sec_sz-1); + irom_base = flash_map.maps[i].load_addr & + ~(esp_info->sec_sz-1); + irom_sz = flash_map.maps[i].size; + if (irom_sz & (esp_info->sec_sz-1)) + irom_sz = (irom_sz & ~(esp_info->sec_sz-1)) + + esp_info->sec_sz; + } else if (esp_info->is_drom_address(flash_map.maps[i].load_addr)) { + drom_flash_base = flash_map.maps[i].phy_addr & + ~(esp_info->sec_sz-1); + drom_base = flash_map.maps[i].load_addr & + ~(esp_info->sec_sz-1); + drom_sz = flash_map.maps[i].size; + if (drom_sz & (esp_info->sec_sz-1)) + drom_sz = (drom_sz & ~(esp_info->sec_sz-1)) + + esp_info->sec_sz; + } + } + } + + if (BANK_SUBNAME(bank, ".irom")) { + esp_info->hw_flash_base = irom_flash_base; + bank->base = irom_base; + bank->size = irom_sz; + } else if (BANK_SUBNAME(bank, ".drom")) { + esp_info->hw_flash_base = drom_flash_base; + bank->base = drom_base; + bank->size = drom_sz; + } else { + esp_info->hw_flash_base = 0; + bank->size = esp_flash_get_size(bank); + if (bank->size == 0) { + LOG_ERROR("Failed to probe flash, size %d KB", bank->size/1024); + return ERROR_FAIL; + } + LOG_INFO("Auto-detected flash bank '%s' size %d KB", bank->name, bank->size/1024); + } + LOG_INFO("Using flash bank '%s' size %d KB", bank->name, bank->size/1024); + + if (bank->size) { + /* Bank size can be 0 for IRON/DROM emulated banks when there is no app in flash */ + bank->num_sectors = bank->size / esp_info->sec_sz; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (bank->sectors == NULL) { + LOG_ERROR("Failed to alloc mem for sectors!"); + return ERROR_FAIL; + } + for (int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i*esp_info->sec_sz; + bank->sectors[i].size = esp_info->sec_sz; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + } + LOG_DEBUG("allocated %d sectors", bank->num_sectors); + esp_info->probed = 1; + + return ERROR_OK; +} + +int esp_flash_auto_probe(struct flash_bank *bank) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + if (esp_info->probed) + return ERROR_OK; + return esp_flash_probe(bank); +} + +static int esp_flash_bp_op_state_init(struct target *target, + struct algorithm_run_data *run, + struct esp_flash_bp_op_state *state) +{ + /* aloocate target buffer for temp storage of flash sections contents when modifying + * instruction */ + LOG_DEBUG("SEC_SIZE %d", state->esp_info->sec_sz); + int ret = target_alloc_alt_working_area(target, + 2*(state->esp_info->sec_sz), + &state->target_buf); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to alloc target buffer for insn sectors!"); + return ret; + } + /* insn sectors buffer */ + algorithm_user_arg_set_uint(run, 3, state->target_buf->address); + + return ERROR_OK; +} + +static void esp_flash_bp_op_state_cleanup(struct target *target, + struct algorithm_run_data *run, + struct esp_flash_bp_op_state *state) +{ + if (!state->target_buf) + return; + target_free_alt_working_area(target, state->target_buf); +} + +int esp_flash_breakpoint_add(struct target *target, + struct breakpoint *breakpoint, + struct esp_flash_breakpoint *sw_bp) +{ + struct esp_flash_bank *esp_info; + struct algorithm_run_data run; + struct flash_bank *bank; + struct esp_flash_bp_op_state op_state; + struct mem_param mp; + + /* flash belongs to root target, so we need to find flash using it instead of core + * sub-target */ + int ret = get_flash_bank_by_addr(target, breakpoint->address, true, &bank); + if (ret != ERROR_OK) { + LOG_ERROR("%s: Failed to get flash bank (%d)!", target_name(target), ret); + return ret; + } + + /* can set set breakpoints in mapped app regions only */ + if (!BANK_SUBNAME(bank, ".irom")) { + LOG_ERROR("%s: Can not set BP outside of IROM (BP addr " TARGET_ADDR_FMT ")!", + target_name(target), + breakpoint->address); + return ERROR_FAIL; + } + + esp_info = bank->driver_priv; + + op_state.esp_info = esp_info; + LOG_DEBUG("SEC_SIZE %d", esp_info->sec_sz); + + ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + run.stack_size = 1300; + run.usr_func_arg = &op_state; + run.usr_func_init = (algorithm_usr_func_init_t)esp_flash_bp_op_state_init; + run.usr_func_done = (algorithm_usr_func_done_t)esp_flash_bp_op_state_cleanup; + + sw_bp->oocd_bp = breakpoint; + sw_bp->bank = bank; + + init_mem_param(&mp, 2 /*2nd usr arg*/, 3 /*size in bytes*/, PARAM_IN); + run.mem_args.params = ∓ + run.mem_args.count = 1; + uint32_t bp_flash_addr = esp_info->hw_flash_base + + (breakpoint->address - bank->base); + ret = esp_info->run_func_image(target, + &run, + 4 /*args num*/, + ESP_STUB_CMD_FLASH_BP_SET /*cmd*/, + bp_flash_addr /*bp_addr*/, + 0 /*address to store insn*/, + 0 /*address to store insn sectors*/); + if (ret != ERROR_OK) { + LOG_ERROR("%s: Failed to run flasher stub (%d)!", target_name(target), ret); + destroy_mem_param(&mp); + sw_bp->oocd_bp = NULL; + return ret; + } + if (run.ret_code == 0) { + LOG_ERROR("%s: Failed to set bp (%" PRId64 ")!", target_name(target), run.ret_code); + destroy_mem_param(&mp); + sw_bp->oocd_bp = NULL; + return ERROR_FAIL; + } + sw_bp->insn_sz = (uint8_t)run.ret_code; + /* sanity check for instructionb buffer overflow */ + assert(sw_bp->insn_sz <= sizeof(sw_bp->insn)); + memcpy(sw_bp->insn, mp.value, sw_bp->insn_sz); + destroy_mem_param(&mp); + LOG_DEBUG( + "%s: Placed flash SW breakpoint at " TARGET_ADDR_FMT + ", insn [%02x %02x %02x %02x] %d bytes", + target_name(target), + breakpoint->address, + sw_bp->insn[0], + sw_bp->insn[1], + sw_bp->insn[2], + sw_bp->insn[3], + sw_bp->insn_sz); + + return ERROR_OK; +} + +int esp_flash_breakpoint_remove(struct target *target, + struct esp_flash_breakpoint *sw_bp) +{ + struct flash_bank *bank = (struct flash_bank *)(sw_bp->bank); + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + struct esp_flash_bp_op_state op_state; + struct mem_param mp; + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + op_state.esp_info = esp_info; + run.stack_size = 1300; + run.usr_func_arg = &op_state; + run.usr_func_init = (algorithm_usr_func_init_t)esp_flash_bp_op_state_init; + run.usr_func_done = (algorithm_usr_func_done_t)esp_flash_bp_op_state_cleanup; + + init_mem_param(&mp, 2 /*2nd usr arg*/, sw_bp->insn_sz /*size in bytes*/, PARAM_OUT); + memcpy(mp.value, sw_bp->insn, sw_bp->insn_sz); + run.mem_args.params = ∓ + run.mem_args.count = 1; + + uint32_t bp_flash_addr = esp_info->hw_flash_base + + (sw_bp->oocd_bp->address - bank->base); + LOG_DEBUG( + "%s: Remove flash SW breakpoint at " TARGET_ADDR_FMT + ", insn [%02x %02x %02x %02x] %d bytes", + target_name(target), + sw_bp->oocd_bp->address, + sw_bp->insn[0], + sw_bp->insn[1], + sw_bp->insn[2], + sw_bp->insn[3], + sw_bp->insn_sz); + ret = esp_info->run_func_image(target, + &run, + 4 /*args num*/, + ESP_STUB_CMD_FLASH_BP_CLEAR /*cmd*/, + bp_flash_addr /*bp_addr*/, + 0 /*address with insn*/, + 0 /*address to store insn sectors*/); + destroy_mem_param(&mp); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to clear bp (%" PRId64 ")!", run.ret_code); + return ERROR_FAIL; + } + + sw_bp->oocd_bp = NULL; + return ret; +} + +static int esp_flash_calc_hash(struct flash_bank *bank, uint8_t *hash, + uint32_t offset, uint32_t count) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + + if (offset & 0x3UL) { + LOG_ERROR("Unaligned offset!"); + return ERROR_FAIL; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + run.stack_size = 1024 + ESP_STUB_RDWR_BUFF_SIZE; + + struct mem_param mp; + init_mem_param(&mp, + 3 /*2nd usr arg*/, + 32 /*sha256 hash size in bytes*/, + PARAM_IN); + run.mem_args.params = ∓ + run.mem_args.count = 1; + + ret = esp_info->run_func_image(bank->target, + &run, + 4 /*args num*/, + ESP_STUB_CMD_FLASH_CALC_HASH /*cmd*/, + esp_info->hw_flash_base + offset, + count, + 0 /*address to store hash value*/); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + destroy_mem_param(&mp); + return ret; + } + if (run.ret_code != ESP_STUB_ERR_OK) { + LOG_ERROR("Failed to get hash value (%" PRId64 ")!", run.ret_code); + ret = ERROR_FAIL; + } else + memcpy(hash, mp.value, 32); + destroy_mem_param(&mp); + return ret; +} + +static int esp_flash_boost_clock_freq(struct flash_bank *bank, int boost) +{ + struct esp_flash_bank *esp_info = bank->driver_priv; + struct algorithm_run_data run; + int new_cpu_freq = -1; /* set to max level */ + + int ret = esp_flasher_algorithm_init(&run, esp_info->stub_hw, esp_info->get_stub(bank)); + if (ret != ERROR_OK) + return ret; + + /* restore */ + if (boost == 0) + new_cpu_freq = esp_info->old_cpu_freq; + + run.stack_size = 1024; + ret = esp_info->run_func_image(bank->target, + &run, + 2, + ESP_STUB_CMD_CLOCK_CONFIGURE, + new_cpu_freq); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to run flasher stub (%d)!", ret); + return ERROR_FAIL; + } + esp_info->old_cpu_freq = (int)run.ret_code; + LOG_DEBUG("%s old_freq (%d) new_freq (%d)", + __func__, + esp_info->old_cpu_freq, + new_cpu_freq); + return ERROR_OK; +} + +static int esp_target_to_flash_bank(struct target *target, + struct flash_bank **bank, char *bank_name_suffix, bool probe) +{ + if (target == NULL || bank == NULL) + return ERROR_FAIL; + + char bank_name[64]; + int retval = snprintf(bank_name, + sizeof(bank_name), + "%s.%s", + target_name(target), + bank_name_suffix); + if (retval == sizeof(bank_name)) { + LOG_ERROR("Failed to build bank name string!"); + return ERROR_FAIL; + } + if (probe) { + retval = get_flash_bank_by_name(bank_name, bank); + if (retval != ERROR_OK || bank == NULL) { + LOG_ERROR("Failed to find bank '%s'!", bank_name); + return retval; + } + } else {/* noprobe */ + *bank = get_flash_bank_by_name_noprobe(bank_name); + if (*bank == NULL) { + LOG_ERROR("Failed to find bank '%s'!", bank_name); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int esp_flash_appimage_base_update(struct target *target, + char *bank_name_suffix, + uint32_t appimage_flash_base) +{ + struct flash_bank *bank; + struct esp_flash_bank *esp_info; + + int retval = esp_target_to_flash_bank(target, &bank, bank_name_suffix, false); + if (retval != ERROR_OK) + return ERROR_FAIL; + + esp_info = (struct esp_flash_bank *)bank->driver_priv; + esp_info->probed = 0; + esp_info->appimage_flash_base = appimage_flash_base; + retval = bank->driver->auto_probe(bank); + return retval; +} + +COMMAND_HELPER(esp_flash_cmd_appimage_flashoff_do, struct target *target) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Flash offset not specified!"); + return ERROR_FAIL; + } + + /* update app image base */ + uint32_t appimage_flash_base = strtoul(CMD_ARGV[0], NULL, 16); + + int ret = esp_flash_appimage_base_update(target, "irom", appimage_flash_base); + if (ret != ERROR_OK) + return ret; + ret = esp_flash_appimage_base_update(target, "drom", appimage_flash_base); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_flash_cmd_appimage_flashoff) +{ + return CALL_COMMAND_HANDLER(esp_flash_cmd_appimage_flashoff_do, + get_current_target(CMD_CTX)); +} + +static int esp_flash_set_compression(struct target *target, + char *bank_name_suffix, + int compression) +{ + struct flash_bank *bank; + struct esp_flash_bank *esp_info; + + int retval = esp_target_to_flash_bank(target, &bank, bank_name_suffix, true); + if (retval != ERROR_OK) + return ERROR_FAIL; + + esp_info = (struct esp_flash_bank *)bank->driver_priv; + esp_info->compression = compression; + return ERROR_OK; +} + +COMMAND_HELPER(esp_flash_cmd_set_compression, struct target *target) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Compression not specified!"); + return ERROR_FAIL; + } + + int compression = 0; + + if (0 == strcmp("on", CMD_ARGV[0])) { + LOG_DEBUG("Flash compressed upload is on"); + compression = 1; + } else if (0 == strcmp("off", CMD_ARGV[0])) { + LOG_DEBUG("Flash compressed upload is off"); + compression = 0; + } else { + LOG_DEBUG("unknown flag"); + return ERROR_FAIL; + } + + return esp_flash_set_compression(target, "flash", compression); +} + +COMMAND_HANDLER(esp_flash_cmd_compression) +{ + return CALL_COMMAND_HANDLER(esp_flash_cmd_set_compression, + get_current_target(CMD_CTX)); +} + +static int esp_flash_verify_bank_hash(struct target *target, + uint32_t offset, + const char *file_name) +{ + uint8_t file_hash[TC_SHA256_DIGEST_SIZE], target_hash[TC_SHA256_DIGEST_SIZE]; + uint8_t *buffer_file; + struct fileio *fileio; + size_t filesize, length, read_cnt; + int differ, retval; + struct flash_bank *bank; + + retval = esp_target_to_flash_bank(target, &bank, "flash", true); + if (retval != ERROR_OK) + return ERROR_FAIL; + + if (offset > bank->size) { + LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", + offset); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + retval = fileio_open(&fileio, file_name, FILEIO_READ, FILEIO_BINARY); + if (retval != ERROR_OK) { + LOG_ERROR("Could not open file"); + return retval; + } + + retval = fileio_size(fileio, &filesize); + if (retval != ERROR_OK) { + fileio_close(fileio); + return retval; + } + + length = MIN(filesize, bank->size - offset); + + if (!length) { + LOG_INFO("Nothing to compare with flash bank"); + fileio_close(fileio); + return ERROR_OK; + } + + if (length != filesize) + LOG_WARNING("File content exceeds flash bank size. Only comparing the " + "first %zu bytes of the file", length); + + LOG_DEBUG("File size: %zu bank_size: %u offset: %u", + filesize, bank->size, offset); + + buffer_file = malloc(length); + if (buffer_file == NULL) { + LOG_ERROR("Out of memory"); + fileio_close(fileio); + return ERROR_FAIL; + } + + retval = fileio_read(fileio, length, buffer_file, &read_cnt); + fileio_close(fileio); + if (retval != ERROR_OK || read_cnt != length) { + LOG_ERROR("File read failure"); + free(buffer_file); + return retval; + } + + retval = esp_calc_hash(buffer_file, length, file_hash); + free(buffer_file); + if (retval != ERROR_OK) { + LOG_ERROR("File sha256 calculation failure"); + return retval; + } + + retval = esp_flash_calc_hash(bank, target_hash, offset, length); + if (retval != ERROR_OK) { + LOG_ERROR("Flash sha256 calculation failure"); + return retval; + } + + differ = memcmp(file_hash, target_hash, TC_SHA256_DIGEST_SIZE); + + if (differ) { + LOG_ERROR("**** Verification failure! ****"); + LOG_ERROR("target_hash %x%x%x...%x%x%x", + target_hash[0], target_hash[1], target_hash[2], + target_hash[29], target_hash[30], target_hash[31]); + LOG_ERROR("file_hash: %x%x%x...%x%x%x", + file_hash[0], file_hash[1], file_hash[2], + file_hash[29], file_hash[30], file_hash[31]); + } + + return differ ? ERROR_FAIL : ERROR_OK; +} + +COMMAND_HELPER(esp_flash_parse_cmd_verify_bank_hash, struct target *target) +{ + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + uint32_t offset = 0; + + if (CMD_ARGC > 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); + + return esp_flash_verify_bank_hash(target, offset, CMD_ARGV[1]); +} + +COMMAND_HANDLER(esp_flash_cmd_verify_bank_hash) +{ + return CALL_COMMAND_HANDLER(esp_flash_parse_cmd_verify_bank_hash, + get_current_target(CMD_CTX)); +} + +COMMAND_HELPER(esp_flash_parse_cmd_clock_boost, struct target *target) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Clock boost flag not specified!"); + return ERROR_FAIL; + } + + int boost = 0; + + if (0 == strcmp("on", CMD_ARGV[0])) { + LOG_DEBUG("Clock boost is on"); + boost = 1; + } else if (0 == strcmp("off", CMD_ARGV[0])) { + LOG_DEBUG("Clock boost is off"); + boost = 0; + } else { + LOG_DEBUG("unknown flag"); + return ERROR_FAIL; + } + + struct flash_bank *bank; + int retval = esp_target_to_flash_bank(target, &bank, "flash", true); + if (retval != ERROR_OK) + return ERROR_FAIL; + + return esp_flash_boost_clock_freq(bank, boost); +} + +COMMAND_HANDLER(esp_flash_cmd_clock_boost) +{ + return CALL_COMMAND_HANDLER(esp_flash_parse_cmd_clock_boost, + get_current_target(CMD_CTX)); +} + +const struct command_registration esp_flash_exec_flash_command_handlers[] = { + { + .name = "appimage_offset", + .handler = esp_flash_cmd_appimage_flashoff, + .mode = COMMAND_ANY, + .help = + "Set offset of application image in flash. Use -1 to debug the first application image from partition table.", + .usage = "offset", + }, + { + .name = "compression", + .handler = esp_flash_cmd_compression, + .mode = COMMAND_ANY, + .help = + "Set compression flag", + .usage = "['on'|'off']", + }, + { + .name = "verify_bank_hash", + .handler = esp_flash_cmd_verify_bank_hash, + .mode = COMMAND_ANY, + .help = "Perform a comparison between the file and the contents of the " + "flash bank using SHA256 hash values. Allow optional offset from beginning of the bank " + "(defaults to zero).", + .usage = "bank_id filename [offset]", + }, + { + .name = "flash_stub_clock_boost", + .handler = esp_flash_cmd_clock_boost, + .mode = COMMAND_ANY, + .help = + "Set cpu clock freq to the max level. Use 'off' to restore the clock speed", + .usage = "['on'|'off']", + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/flash/nor/esp_flash.h b/src/flash/nor/esp_flash.h new file mode 100644 index 0000000000..5106ee8667 --- /dev/null +++ b/src/flash/nor/esp_flash.h @@ -0,0 +1,142 @@ +/*************************************************************************** + * Generic flash driver for Espressif chips * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FLASH_ESP_H +#define FLASH_ESP_H + +#include +#include +#include +#include +#include + +struct esp_flash_apptrace_hw { + int (*info_init)(struct target *target, + target_addr_t ctrl_addr, + target_addr_t *old_ctrl_addr); + int (*data_len_read)(struct target *target, + uint32_t *block_id, + uint32_t *len); + int (*data_read)(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack); + int (*ctrl_reg_read)(struct target *target, + uint32_t *block_id, + uint32_t *len, + bool *conn); + int (*ctrl_reg_write)(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data); + int (*usr_block_write)(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size); + uint8_t *(*usr_block_get)(uint8_t *buffer, uint32_t *size); + uint32_t (*block_max_size_get)(struct target *target); + uint32_t (*usr_block_max_size_get)(struct target *target); +}; + +struct esp_flasher_stub_config { + const uint8_t *code; + uint32_t code_sz; + const uint8_t *data; + uint32_t data_sz; + target_addr_t entry_addr; + uint32_t bss_sz; + uint32_t first_user_reg_param; + target_addr_t apptrace_ctrl_addr; + uint32_t stack_data_pool_sz; +}; + +/* ESP flash data. + It should be the first member of flash data structs for concrete chips. + For example see ESP32 flash driver implementation. */ +struct esp_flash_bank { + int probed; + /* Sector size */ + uint32_t sec_sz; + /* Base address of the bank in the flash, 0 - for HW flash bank, non-zero for special + * IROM/DROM fake banks */ + /* Those fake banks are necessary for generating proper memory map for GDB and using flash + * breakpoints */ + uint32_t hw_flash_base; + /* Minimal offset for erase/write on flash bank */ + uint32_t flash_min_offset; + /* Offset of the application image in the HW flash bank */ + uint32_t appimage_flash_base; + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank); + /* function to run algorithm on Xtensa target */ + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...); + bool (*is_irom_address)(target_addr_t addr); + bool (*is_drom_address)(target_addr_t addr); + const struct esp_flash_apptrace_hw *apptrace_hw; + const struct algorithm_hw *stub_hw; + /* Upload compressed or uncompressed image */ + int compression; + /* Stub cpu frequency before boost */ + int old_cpu_freq; +}; + +struct esp_flash_breakpoint { + struct breakpoint *oocd_bp; + /* original insn or part of it */ + uint8_t insn[4]; + /* original insn size. Actually this is size of break instruction. */ + uint8_t insn_sz; + struct flash_bank *bank; +}; + +int esp_flash_init(struct esp_flash_bank *esp_info, uint32_t sec_sz, + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...), + bool (*is_irom_address)(target_addr_t addr), + bool (*is_drom_address)(target_addr_t addr), + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank), + const struct esp_flash_apptrace_hw *apptrace_hw, + const struct algorithm_hw *stub_hw); +int esp_flash_protect(struct flash_bank *bank, int set, int first, int last); +int esp_flash_protect_check(struct flash_bank *bank); +int esp_flash_blank_check(struct flash_bank *bank); +int esp_flash_erase(struct flash_bank *bank, int first, int last); +int esp_flash_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count); +int esp_flash_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count); +int esp_flash_probe(struct flash_bank *bank); +int esp_flash_auto_probe(struct flash_bank *bank); +int esp_flash_breakpoint_add(struct target *target, + struct breakpoint *breakpoint, + struct esp_flash_breakpoint *sw_bp); +int esp_flash_breakpoint_remove(struct target *target, + struct esp_flash_breakpoint *sw_bp); + +extern const struct command_registration esp_flash_exec_flash_command_handlers[]; + +COMMAND_HELPER(esp_flash_cmd_appimage_flashoff_do, struct target *target); +COMMAND_HELPER(esp_flash_cmd_set_compression, struct target *target); +COMMAND_HELPER(esp_flash_parse_cmd_verify_bank_hash, struct target *target); +COMMAND_HELPER(esp_flash_parse_cmd_clock_boost, struct target *target); + +#endif /*FLASH_ESP_H*/ diff --git a/src/flash/nor/esp_riscv.c b/src/flash/nor/esp_riscv.c new file mode 100644 index 0000000000..7b90b0fc1d --- /dev/null +++ b/src/flash/nor/esp_riscv.c @@ -0,0 +1,52 @@ +/*************************************************************************** + * ESP RISCV flash driver for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "esp_riscv.h" +#include +#include + +static const struct esp_flash_apptrace_hw s_esp_riscv_flash_apptrace_hw = { + .info_init = esp_riscv_apptrace_info_init, + .data_len_read = esp_riscv_apptrace_data_len_read, + .data_read = esp_riscv_apptrace_data_read, + .ctrl_reg_read = esp_riscv_apptrace_ctrl_reg_read, + .ctrl_reg_write = esp_riscv_apptrace_ctrl_reg_write, + .usr_block_write = esp_riscv_apptrace_usr_block_write, + .usr_block_get = esp_apptrace_usr_block_get, + .block_max_size_get = esp_riscv_apptrace_block_max_size_get, + .usr_block_max_size_get = esp_riscv_apptrace_usr_block_max_size_get, +}; + +int esp_riscv_flash_init(struct esp_riscv_flash_bank *esp_info, uint32_t sec_sz, + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...), + bool (*is_irom_address)(target_addr_t addr), + bool (*is_drom_address)(target_addr_t addr), + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank)) +{ + memset(esp_info, 0, sizeof(*esp_info)); + return esp_flash_init(&esp_info->esp, sec_sz, run_func_image, is_irom_address, + is_drom_address, get_stub, &s_esp_riscv_flash_apptrace_hw, + &riscv_algo_hw); + +} diff --git a/src/flash/nor/esp_riscv.h b/src/flash/nor/esp_riscv.h new file mode 100644 index 0000000000..87121c7dcd --- /dev/null +++ b/src/flash/nor/esp_riscv.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Generic flash driver for Espressif RISCV chips * + * Copyright (C) 2021 Espressif Systems Ltd. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FLASH_ESP_RISCV_H +#define FLASH_ESP_RISCV_H + +#include "esp_flash.h" + +/* ESP RISCV flash data. + It should be the first member of flash data structs for concrete chips. + For example see ESP32-C3 flash driver implementation. */ +struct esp_riscv_flash_bank { + struct esp_flash_bank esp; +}; + +int esp_riscv_flash_init(struct esp_riscv_flash_bank *esp_info, uint32_t sec_sz, + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...), + bool (*is_irom_address)(target_addr_t addr), + bool (*is_drom_address)(target_addr_t addr), + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank)); + + +#endif /*FLASH_ESP_RISCV_H*/ diff --git a/src/flash/nor/esp_xtensa.c b/src/flash/nor/esp_xtensa.c index e57ac986a1..f2f9b5fa81 100644 --- a/src/flash/nor/esp_xtensa.c +++ b/src/flash/nor/esp_xtensa.c @@ -1,7 +1,6 @@ /*************************************************************************** - * Generic flash driver for Espressif Xtensa chips * - * Copyright (C) 2017 Espressif Systems Ltd. * - * Author: Alexey Gerenkov * + * ESP Xtensa flash driver for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -19,1495 +18,39 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ -/* - * Overview - * -------- - * Like many other flash drivers this one uses special binary program (stub) running on target - * to perform all operations and communicate to the host. Stub has entry function which accepts - * variable number of arguments and therefore can handle different flash operation requests. - * Only the first argument of the stub entry function is mandatory for all operations it must - * specify the type of flash function to perform (read, write etc.). Actually stub main function - * is a dispatcher which determines the type of flash operation to perform, retrieves other - * arguments and calls corresponding handler. In C notation entry function looks like the following: - - * int stub_main(int cmd, ...); - - * In general every flash operation consists of the following steps: - * 1) Stub is loaded to target. - * 2) Necessary arguments are prepared and stub's main function is called. - * 3) Stub does the work and returns the result. - - * Stub Loading - * ------------ - * To run stub its code and data sections must be loaded to the target. It is done using working area API. - * But since code and data address spaces are separated in ESP32 it is necessary to have two configured - * working areas: one in code address space and another one in data space. So driver allocates chunks - * in respective pools and writes stub sections to them. It is important that the both stub sections reside - * at the beginning of respective working areas because stub code is linked as ELF and therefore it is - * position dependent. So target memory for stub code and data must be allocated first. - - * Stub Execution - * -------------- - * Special wrapping code is used to enter and exit the stub's main function. It prepares register arguments - * before Windowed ABI call to stub entry and upon return from it executes break command to indicate to OpenOCD - * that operation is finished. - - * Flash Data Transfers - * -------------------- - * To transfer data from/to target a buffer should be allocated at ESP32 side. Also during the data transfer - * target and host must maintain the state of that buffer (read/write pointers etc.). So host needs to check - * the state of that buffer periodically and write to or read from it (depending on flash operation type). - * ESP32 does not support access to its memory via JTAG when it is not halted, so accessing target memory would - * requires halting the CPUs every time the host needs to check if there are incoming data or free space available - * in the buffer. This fact can slow down flash write/read operations dramatically. To avoid this flash driver and - * stub use application level tracing module API to transfer the data in 'non-stop' mode. - * - */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif - -#include "imp.h" -#include -#include -#include -#include #include "esp_xtensa.h" -#include "time_support.h" -#include "contrib/loaders/flash/esp/stub_flasher.h" - -#include - -#define ESP_XTENSA_FLASH_MIN_OFFSET 0x1000 /* protect secure boot digest data */ -#define ESP_XTENSA_RW_TMO 20000 /* ms */ -#define ESP_XTENSA_ERASE_TMO 60000 /* ms */ - -struct esp_xtensa_rw_args { - int (*xfer)(struct target *target, uint32_t block_id, uint32_t len, void *priv); - uint8_t *buffer; - uint32_t count; - uint32_t total_count; - bool connected; -}; - -struct esp_xtensa_write_state { - struct esp_xtensa_rw_args rw; - uint32_t prev_block_id; - struct working_area *target_buf; - struct esp_xtensa_flash_bank *esp_xtensa_info; - struct working_area *stub_wargs_area; - struct esp_xtensa_stub_flash_write_args stub_wargs; -}; - -struct esp_xtensa_read_state { - struct esp_xtensa_rw_args rw; - uint8_t *rd_buf; -}; - -struct esp_xtensa_erase_check_args { - struct working_area *erased_state_buf; - uint32_t num_sectors; -}; - -struct esp_xtensa_flash_bp_op_state { - struct working_area *target_buf; - struct esp_xtensa_flash_bank *esp_xtensa_info; +#include +#include + +#define ESP_XTENSA_FLASH_MIN_OFFSET 0x1000 /* protect secure boot digest data + **/ + +static const struct esp_flash_apptrace_hw s_esp_xtensa_flash_apptrace_hw = { + .data_len_read = esp_xtensa_apptrace_data_len_read, + .data_read = esp_xtensa_apptrace_data_read, + .ctrl_reg_read = esp_xtensa_apptrace_ctrl_reg_read, + .ctrl_reg_write = esp_xtensa_apptrace_ctrl_reg_write, + .usr_block_write = esp_xtensa_apptrace_usr_block_write, + .usr_block_get = esp_apptrace_usr_block_get, + .block_max_size_get = esp_xtensa_apptrace_block_max_size_get, + .usr_block_max_size_get = esp_xtensa_apptrace_usr_block_max_size_get, }; -static int esp_xtensa_compress(const uint8_t *in, uint32_t in_len, uint8_t **out, uint32_t *out_len) -{ - z_stream strm; - int wbits = -MAX_WBITS; /*deflate */ - int level = Z_DEFAULT_COMPRESSION; /*Z_BEST_SPEED; */ - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - - if (deflateInit2(&strm, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, - Z_DEFAULT_STRATEGY) != Z_OK) { - LOG_ERROR("deflateInit2 error!"); - return ERROR_FAIL; - } - - strm.avail_out = deflateBound(&strm, (uLong)in_len); - - /* Some compression methods may need a little more space */ - strm.avail_out += 100; - - if (strm.avail_out > INT_MAX) { - deflateEnd(&strm); - return ERROR_FAIL; - } - - *out = (uint8_t *)malloc((int)strm.avail_out); - if (*out == NULL) { - LOG_ERROR("out buffer allocation failed!"); - return ERROR_FAIL; - } - strm.next_out = *out; - strm.next_in = (uint8_t *)in; - strm.avail_in = (uInt)in_len; - - /* always compress in one pass - the return value holds the entire - * decompressed data anyway, so there's no reason to do chunked - * decompression */ - if (deflate(&strm, Z_FINISH) != Z_STREAM_END) { - free(*out); - deflateEnd(&strm); - LOG_ERROR("not enough output space"); - return ERROR_FAIL; - } - - deflateEnd(&strm); - - if (strm.total_out > INT_MAX) { - free(*out); - LOG_ERROR("too much output"); - return ERROR_FAIL; - } - - *out_len = strm.total_out; - - LOG_DEBUG("inlen:(%u) outlen:(%u)!", in_len, *out_len); - - return ERROR_OK; -} - -static int esp_xtensa_calc_hash(const uint8_t *data, size_t datalen, uint8_t *hash) -{ - if (data == NULL || hash == NULL || datalen == 0) - return ERROR_FAIL; - - struct tc_sha256_state_struct sha256_state; - - if (tc_sha256_init(&sha256_state) != TC_CRYPTO_SUCCESS) { - LOG_ERROR("tc_sha256_init failed!"); - return ERROR_FAIL; - } - - if (tc_sha256_update(&sha256_state, data, datalen) != TC_CRYPTO_SUCCESS) { - LOG_ERROR("tc_sha256_update failed!"); - return ERROR_FAIL; - } - if (tc_sha256_final(hash, &sha256_state) != TC_CRYPTO_SUCCESS) { - LOG_ERROR("tc_sha256_final failed!"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int esp_xtensa_flasher_image_init(struct xtensa_algo_image *flasher_image, - const struct esp_xtensa_flasher_stub_config *stub_cfg) -{ - if (!stub_cfg) { - LOG_ERROR("Invalid stub!"); - return ERROR_FAIL; - } - - flasher_image->bss_size = stub_cfg->bss_sz; - memset(&flasher_image->image, 0, sizeof(flasher_image->image)); - int ret = image_open(&flasher_image->image, NULL, "build"); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to create image (%d)!", ret); - return ret; - } - flasher_image->image.start_address_set = 1; - flasher_image->image.start_address = stub_cfg->entry_addr; - ret = image_add_section(&flasher_image->image, - 0, - stub_cfg->code_sz, - IMAGE_ELF_PHF_EXEC, - stub_cfg->code); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to create image (%d)!", ret); - image_close(&flasher_image->image); - return ret; - } - ret = image_add_section(&flasher_image->image, 0, stub_cfg->data_sz, 0, stub_cfg->data); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to create image (%d)!", ret); - image_close(&flasher_image->image); - return ret; - } - LOG_DEBUG("base=%08x set=%d", - (unsigned) flasher_image->image.base_address, - flasher_image->image.base_address_set); - return ret; -} - -int esp_xtensa_flash_init(struct esp_xtensa_flash_bank *esp_xtensa_info, uint32_t sec_sz, - int (*run_func_image)(struct target *target, struct xtensa_algo_run_data *run, - struct xtensa_algo_image *image, uint32_t num_args, ...), +int esp_xtensa_flash_init(struct esp_xtensa_flash_bank *esp_info, uint32_t sec_sz, + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...), bool (*is_irom_address)(target_addr_t addr), bool (*is_drom_address)(target_addr_t addr), - const struct esp_xtensa_flasher_stub_config *(*get_stub)(struct flash_bank *bank)) -{ - - esp_xtensa_info->probed = 0; - esp_xtensa_info->sec_sz = sec_sz; - esp_xtensa_info->get_stub = get_stub; - esp_xtensa_info->run_func_image = run_func_image; - esp_xtensa_info->is_irom_address = is_irom_address; - esp_xtensa_info->is_drom_address = is_drom_address; - esp_xtensa_info->hw_flash_base = 0; - esp_xtensa_info->appimage_flash_base = (uint32_t)-1; - esp_xtensa_info->compression = 1; /* enables compression by default */ - esp_xtensa_info->old_cpu_freq = 0; - return ERROR_OK; -} - -int esp_xtensa_protect(struct flash_bank *bank, int set, int first, int last) + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank)) { - return ERROR_FAIL; -} - -int esp_xtensa_protect_check(struct flash_bank *bank) -{ - return ERROR_OK; -} - -int esp_xtensa_blank_check(struct flash_bank *bank) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct xtensa_algo_image flasher_image; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted!"); - return ERROR_TARGET_NOT_HALTED; - } - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1300; - struct mem_param mp; - init_mem_param(&mp, 3 /*3rd usr arg*/, bank->num_sectors /*size in bytes*/, PARAM_IN); - run.mem_args.params = ∓ - run.mem_args.count = 1; - - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 4, - ESP_XTENSA_STUB_CMD_FLASH_ERASE_CHECK /*cmd*/, - esp_xtensa_info->hw_flash_base/esp_xtensa_info->sec_sz /*start*/, - bank->num_sectors /*sectors num*/, - 0 /*address to store sectors' state*/); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - destroy_mem_param(&mp); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to check erase flash (%d)!", run.ret_code); - ret = ERROR_FAIL; - } else { - for (int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = mp.value[i]; - } - destroy_mem_param(&mp); + memset(esp_info, 0, sizeof(*esp_info)); + int ret = esp_flash_init(&esp_info->esp, sec_sz, run_func_image, is_irom_address, + is_drom_address, get_stub, &s_esp_xtensa_flash_apptrace_hw, + &xtensa_algo_hw); + esp_info->esp.flash_min_offset = ESP_XTENSA_FLASH_MIN_OFFSET; return ret; } - -static uint32_t esp_xtensa_get_size(struct flash_bank *bank) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - uint32_t size = 0; - struct xtensa_algo_run_data run; - struct xtensa_algo_image flasher_image; - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1024; - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 1, - ESP_XTENSA_STUB_CMD_FLASH_SIZE); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - return 0; - } - size = run.ret_code; - if (size == 0) - LOG_ERROR("Failed to get flash size!"); - LOG_DEBUG("%s size 0x%x", __func__, size); - return size; -} - -static int esp_xtensa_get_mappings(struct flash_bank *bank, - struct esp_xtensa_flash_bank *esp_xtensa_info, - struct esp_xtensa_flash_mapping *flash_map, - uint32_t appimage_flash_base) -{ - struct xtensa_algo_run_data run; - struct xtensa_algo_image flasher_image; - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1300; - - struct mem_param mp; - init_mem_param(&mp, - 2 /*2nd usr arg*/, - sizeof(struct esp_xtensa_flash_mapping) /*size in bytes*/, - PARAM_IN); - run.mem_args.params = ∓ - run.mem_args.count = 1; - - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 3 /*args num*/, - ESP_XTENSA_STUB_CMD_FLASH_MAP_GET /*cmd*/, - appimage_flash_base, - 0 /*address to store mappings*/); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - destroy_mem_param(&mp); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to get flash maps (%d)!", run.ret_code); - if (run.ret_code == ESP_XTENSA_STUB_ERR_INVALID_IMAGE) - LOG_WARNING( - "Application image is invalid! Check configured binary flash offset 'appimage_offset'."); - ret = ERROR_FAIL; - } else { - memcpy(flash_map, mp.value, sizeof(struct esp_xtensa_flash_mapping)); - if (flash_map->maps_num == 0) - LOG_WARNING("Empty flash mapping!"); - for (uint32_t i = 0; i < flash_map->maps_num; i++) - LOG_INFO("Flash mapping %d: 0x%x -> 0x%x, %d KB", - i, - flash_map->maps[i].phy_addr, - flash_map->maps[i].load_addr, - flash_map->maps[i].size/1024); - } - destroy_mem_param(&mp); - return ret; -} - -int esp_xtensa_erase(struct flash_bank *bank, int first, int last) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct xtensa_algo_image flasher_image; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - assert((0 <= first) && (first <= last) && (last < bank->num_sectors)); - if (esp_xtensa_info->hw_flash_base + first*esp_xtensa_info->sec_sz < - ESP_XTENSA_FLASH_MIN_OFFSET) { - LOG_ERROR("Invalid offset!"); - return ERROR_FAIL; - } - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1024; - run.tmo = ESP_XTENSA_ERASE_TMO; - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 3, - ESP_XTENSA_STUB_CMD_FLASH_ERASE, - /* cmd */ - esp_xtensa_info->hw_flash_base + first*esp_xtensa_info->sec_sz, - /* start addr */ - (last-first+1)*esp_xtensa_info->sec_sz); /* size */ - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to erase flash (%d)!", run.ret_code); - ret = ERROR_FAIL; - } - return ret; -} - -static int esp_xtensa_rw_do(struct target *target, void *priv) -{ - struct duration algo_time, tmo_time; - struct esp_xtensa_rw_args *rw = (struct esp_xtensa_rw_args *)priv; - int retval = ERROR_OK, busy_num = 0; - - if (duration_start(&algo_time) != 0) { - LOG_ERROR("Failed to start data write time measurement!"); - return ERROR_FAIL; - } - while (rw->total_count < rw->count) { - uint32_t block_id = 0, len = 0; - LOG_DEBUG("Transfer block on %s", target_name(target)); - retval = esp_xtensa_apptrace_data_len_read(target, &block_id, &len); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to read apptrace status (%d)!", retval); - return retval; - } - /* transfer block */ - LOG_DEBUG("Transfer block %d, %d bytes", block_id, len); - retval = rw->xfer(target, block_id, len, rw); - if (retval == ERROR_WAIT) { - LOG_DEBUG("Block not ready"); - if (busy_num++ == 0) { - if (duration_start(&tmo_time) != 0) { - LOG_ERROR("Failed to start data write time measurement!"); - return ERROR_FAIL; - } - } else { - /* if no transfer check tmo */ - if (duration_measure(&tmo_time) != 0) { - LOG_ERROR("Failed to stop algo run measurement!"); - return ERROR_FAIL; - } - if (1000*duration_elapsed(&tmo_time) > ESP_XTENSA_RW_TMO) { - LOG_ERROR("Transfer data tmo!"); - return ERROR_WAIT; - } - } - } else if (retval != ERROR_OK) { - LOG_ERROR("Failed to transfer flash data block (%d)!", retval); - return retval; - } else - busy_num = 0; - alive_sleep(10); - if (target->state != TARGET_DEBUG_RUNNING) { - LOG_ERROR("Algorithm accidentally stopped (%d)!", target->state); - return ERROR_FAIL; - } - } - if (duration_measure(&algo_time) != 0) { - LOG_ERROR("Failed to stop data write measurement!"); - return ERROR_FAIL; - } - LOG_INFO("PROF: Data transferred in %g ms @ %g KB/s", - duration_elapsed(&algo_time)*1000, - duration_kbps(&algo_time, rw->total_count)); - - return ERROR_OK; -} - -static int esp_xtensa_write_xfer(struct target *target, uint32_t block_id, uint32_t len, void *priv) -{ - struct esp_xtensa_write_state *state = (struct esp_xtensa_write_state *)priv; - int retval; - - /* check for target to get connected */ - if (!state->rw.connected) { - retval = - esp_xtensa_apptrace_ctrl_reg_read(target, NULL, NULL, &state->rw.connected); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to read apptrace control reg (%d)!", retval); - return retval; - } - if (!state->rw.connected) - return ERROR_WAIT; - } - - if (state->prev_block_id == block_id) - return ERROR_WAIT; - - uint32_t wr_sz = state->rw.count - state->rw.total_count < - esp_xtensa_apptrace_usr_block_max_size_get(target) ? - state->rw.count - - state->rw.total_count : esp_xtensa_apptrace_usr_block_max_size_get(target); - retval = esp_xtensa_apptrace_usr_block_write(target, - block_id, - state->rw.buffer + state->rw.total_count, - wr_sz); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to write apptrace data (%d)!", retval); - return retval; - } - state->rw.total_count += wr_sz; - state->prev_block_id = block_id; - - return ERROR_OK; -} - -static int esp_xtensa_write_state_init(struct target *target, - struct xtensa_algo_run_data *run, - struct esp_xtensa_write_state *state) -{ - struct duration algo_time; - - /* clear control register, stub will set XTENSA_APPTRACE_HOST_CONNECT bit when it will be - * ready */ - int ret = esp_xtensa_apptrace_ctrl_reg_write(target, - 0 /*block_id*/, - 0 /*len*/, - false /*conn*/, - false /*data*/); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to clear apptrace ctrl reg (%d)!", ret); - return ret; - } - - /* memory buffer */ - if (duration_start(&algo_time) != 0) { - LOG_ERROR("Failed to start workarea alloc time measurement!"); - return ERROR_FAIL; - } - uint32_t buffer_size = 64*1024; - while (target_alloc_alt_working_area_try(target, buffer_size, - &state->target_buf) != ERROR_OK) { - buffer_size /= 2; - if (buffer_size == 0) { - LOG_ERROR("Failed to alloc target buffer for flash data!"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - } - if (duration_measure(&algo_time) != 0) { - LOG_ERROR("Failed to stop workarea alloc measurement!"); - return ERROR_FAIL; - } - LOG_DEBUG("PROF: Allocated target buffer %d bytes in %g ms", - buffer_size, - duration_elapsed(&algo_time)*1000); - - /* alloc memory for stub flash write arguments in data working area */ - if (target_alloc_alt_working_area(target, sizeof(state->stub_wargs), - &state->stub_wargs_area) != ERROR_OK) { - LOG_ERROR("no working area available, can't alloc space for stub flash arguments"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - state->stub_wargs.down_buf_addr = state->target_buf->address; - state->stub_wargs.down_buf_size = state->target_buf->size; - - ret = target_write_buffer(target, state->stub_wargs_area->address, - sizeof(state->stub_wargs), (uint8_t *)&state->stub_wargs); - if (ret != ERROR_OK) { - LOG_ERROR("Write memory at address " TARGET_ADDR_FMT " failed", - state->stub_wargs_area->address); - return ERROR_TARGET_FAILURE; - } - - buf_set_u32(run->priv.stub.reg_params[XTENSA_STUB_ARGS_FUNC_START + 1].value, - 0, - 32, - state->stub_wargs_area->address); - - return ERROR_OK; -} - -static void esp_xtensa_write_state_cleanup(struct target *target, - struct xtensa_algo_run_data *run, - struct esp_xtensa_write_state *state) -{ - struct duration algo_time; - - if (!state->target_buf) - return; - if (duration_start(&algo_time) != 0) - LOG_ERROR("Failed to start workarea alloc time measurement!"); - target_free_alt_working_area(target, state->target_buf); - target_free_alt_working_area(target, state->stub_wargs_area); - if (duration_measure(&algo_time) != 0) - LOG_ERROR("Failed to stop data write measurement!"); - LOG_DEBUG("PROF: Workarea freed in %g ms", duration_elapsed(&algo_time)*1000); -} - -int esp_xtensa_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct esp_xtensa_write_state wr_state; - struct xtensa_algo_image flasher_image; - uint8_t *compressed_buff = NULL; - uint32_t compressed_len = 0; - uint32_t stack_size = 1024 + ESP_XTENSA_STUB_UNZIP_BUFF_SIZE; - - if (esp_xtensa_info->hw_flash_base + offset < ESP_XTENSA_FLASH_MIN_OFFSET) { - LOG_ERROR("Invalid offset!"); - return ERROR_FAIL; - } - if (offset & 0x3UL) { - LOG_ERROR("Unaligned offset!"); - return ERROR_FAIL; - } - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - if (esp_xtensa_info->compression) { - struct duration bench; - duration_start(&bench); - if (esp_xtensa_compress(buffer, count, &compressed_buff, - &compressed_len) != ERROR_OK) { - LOG_ERROR("Compression failed!"); - return ERROR_FAIL; - } - duration_measure(&bench); - LOG_INFO("Compressed %" PRIu32 " bytes to %" PRIu32 " bytes " - "in %fs", - count, - compressed_len, - duration_elapsed(&bench)); - - stack_size += ESP_XTENSA_STUB_IFLATOR_SIZE; - } - - memset(&run, 0, sizeof(run)); - run.stack_size = stack_size; - run.usr_func = esp_xtensa_rw_do; - run.usr_func_arg = &wr_state; - run.usr_func_init = (xtensa_algo_usr_func_init_t)esp_xtensa_write_state_init; - run.usr_func_done = (xtensa_algo_usr_func_done_t)esp_xtensa_write_state_cleanup; - memset(&wr_state, 0, sizeof(struct esp_xtensa_write_state)); - wr_state.rw.buffer = esp_xtensa_info->compression ? compressed_buff : (uint8_t *)buffer; - wr_state.rw.count = esp_xtensa_info->compression ? compressed_len : count; - wr_state.rw.xfer = esp_xtensa_write_xfer; - wr_state.prev_block_id = (uint32_t)-1; - wr_state.esp_xtensa_info = esp_xtensa_info; - /* stub flasher arguments */ - wr_state.stub_wargs.size = wr_state.rw.count; - wr_state.stub_wargs.total_size = count; - wr_state.stub_wargs.start_addr = esp_xtensa_info->hw_flash_base + offset; - wr_state.stub_wargs.down_buf_addr = 0; - wr_state.stub_wargs.down_buf_size = 0; - - ret = esp_xtensa_info->run_func_image( - bank->target, - &run, - &flasher_image, - 2, - esp_xtensa_info->compression ? ESP_XTENSA_STUB_CMD_FLASH_WRITE_DEFLATED : - ESP_XTENSA_STUB_CMD_FLASH_WRITE, - /* cmd */ - 0 - /* esp_xtensa_stub_flash_write_args */); - - if (compressed_buff) - free(compressed_buff); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to write flash (%d)!", run.ret_code); - ret = ERROR_FAIL; - } - return ret; -} - -static int esp_xtensa_read_xfer(struct target *target, uint32_t block_id, uint32_t len, void *priv) -{ - struct esp_xtensa_read_state *state = (struct esp_xtensa_read_state *)priv; - int retval; - - /* check for target to get connected */ - if (!state->rw.connected) { - retval = - esp_xtensa_apptrace_ctrl_reg_read(target, NULL, NULL, &state->rw.connected); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to read apptrace control reg (%d)!", retval); - return retval; - } - if (!state->rw.connected) - return ERROR_WAIT; - } - - if (len == 0) - return ERROR_WAIT; - - retval = esp_xtensa_apptrace_data_read(target, len, state->rd_buf, block_id, 1 /*ack*/); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to read apptrace status (%d)!", retval); - return retval; - } - LOG_DEBUG("DATA %d bytes: %x %x %x %x %x %x %x %x", len, - state->rd_buf[0], state->rd_buf[1], state->rd_buf[2], state->rd_buf[3], - state->rd_buf[4], state->rd_buf[5], state->rd_buf[6], state->rd_buf[7]); - - uint8_t *ptr = state->rd_buf; - while (ptr < state->rd_buf + len) { - uint32_t data_sz = 0; - ptr = esp_apptrace_usr_block_get(ptr, &data_sz); - if (data_sz > 0) - memcpy(state->rw.buffer + state->rw.total_count, ptr, data_sz); - ptr += data_sz; - state->rw.total_count += data_sz; - } - - return ERROR_OK; -} - -static int esp_xtensa_read_state_init(struct target *target, - struct xtensa_algo_run_data *run, - struct esp_xtensa_read_state *state) -{ - /* clear control register, stub will set XTENSA_APPTRACE_HOST_CONNECT bit when it will be - * ready */ - int ret = esp_xtensa_apptrace_ctrl_reg_write(target, - 0 /*block_id*/, - 0 /*len*/, - false /*conn*/, - false /*data*/); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to clear apptrace ctrl reg (%d)!", ret); - return ret; - } - - state->rd_buf = malloc(esp_xtensa_apptrace_block_max_size_get(target)); - if (!state->rd_buf) { - LOG_ERROR("Failed to alloc read buffer!"); - return ERROR_FAIL; - } - return ERROR_OK; -} - -int esp_xtensa_read(struct flash_bank *bank, uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct esp_xtensa_read_state rd_state; - struct xtensa_algo_image flasher_image; - - if (offset & 0x3UL) { - LOG_ERROR("Unaligned offset!"); - return ERROR_FAIL; - } - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1024; - run.usr_func_init = (xtensa_algo_usr_func_init_t)esp_xtensa_read_state_init; - run.usr_func = esp_xtensa_rw_do; - run.usr_func_arg = &rd_state; - memset(&rd_state, 0, sizeof(struct esp_xtensa_read_state)); - rd_state.rw.buffer = buffer; - rd_state.rw.count = count; - rd_state.rw.xfer = esp_xtensa_read_xfer; - - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 3, - ESP_XTENSA_STUB_CMD_FLASH_READ, - /* cmd */ - esp_xtensa_info->hw_flash_base + offset, - /* start addr */ - count); /* size */ - - free(rd_state.rd_buf); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to read flash (%d)!", run.ret_code); - ret = ERROR_FAIL; - } - return ret; -} - -#define BANK_SUBNAME(_b_, _n_) (strcmp((_b_)->name + strlen((_b_)->name) - strlen(_n_), _n_) == 0) - -int esp_xtensa_probe(struct flash_bank *bank) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct esp_xtensa_flash_mapping flash_map = {.maps_num = 0}; - uint32_t irom_base = 0, irom_sz = 0, drom_base = 0, drom_sz = 0, irom_flash_base = 0, - drom_flash_base = 0; - - esp_xtensa_info->probed = 0; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - LOG_DEBUG("Flash size = %d KB @ "TARGET_ADDR_FMT " '%s' - '%s'", - bank->size/1024, - bank->base, - target_name(bank->target), - target_state_name(bank->target)); - - if (bank->sectors) { - free(bank->sectors); - bank->sectors = NULL; - } - - int ret = esp_xtensa_get_mappings(bank, - esp_xtensa_info, - &flash_map, - esp_xtensa_info->appimage_flash_base); - if (ret != ERROR_OK || flash_map.maps_num == 0) { - LOG_WARNING("Failed to get flash mappings (%d)!", ret); - /* if no DROM/IROM mappings so pretend they are at the end of the HW flash bank and - * have zero size to allow correct memory map with non zero RAM region */ - irom_base = drom_base = esp_xtensa_get_size(bank); - } else { - for (uint32_t i = 0; i < flash_map.maps_num; i++) { - if (esp_xtensa_info->is_irom_address(flash_map.maps[i].load_addr)) { - irom_flash_base = flash_map.maps[i].phy_addr & - ~(esp_xtensa_info->sec_sz-1); - irom_base = flash_map.maps[i].load_addr & - ~(esp_xtensa_info->sec_sz-1); - irom_sz = flash_map.maps[i].size; - if (irom_sz & (esp_xtensa_info->sec_sz-1)) - irom_sz = (irom_sz & ~(esp_xtensa_info->sec_sz-1)) + - esp_xtensa_info->sec_sz; - } else if (esp_xtensa_info->is_drom_address(flash_map.maps[i].load_addr)) { - drom_flash_base = flash_map.maps[i].phy_addr & - ~(esp_xtensa_info->sec_sz-1); - drom_base = flash_map.maps[i].load_addr & - ~(esp_xtensa_info->sec_sz-1); - drom_sz = flash_map.maps[i].size; - if (drom_sz & (esp_xtensa_info->sec_sz-1)) - drom_sz = (drom_sz & ~(esp_xtensa_info->sec_sz-1)) + - esp_xtensa_info->sec_sz; - } - } - } - - if (BANK_SUBNAME(bank, ".irom")) { - esp_xtensa_info->hw_flash_base = irom_flash_base; - bank->base = irom_base; - bank->size = irom_sz; - } else if (BANK_SUBNAME(bank, ".drom")) { - esp_xtensa_info->hw_flash_base = drom_flash_base; - bank->base = drom_base; - bank->size = drom_sz; - } else { - esp_xtensa_info->hw_flash_base = 0; - bank->size = esp_xtensa_get_size(bank); - if (bank->size == 0) { - LOG_ERROR("Failed to probe flash, size %d KB", bank->size/1024); - return ERROR_FAIL; - } - LOG_INFO("Auto-detected flash bank '%s' size %d KB", bank->name, bank->size/1024); - } - LOG_INFO("Using flash bank '%s' size %d KB", bank->name, bank->size/1024); - - if (bank->size) { - /* Bank size can be 0 for IROM/DROM emulated banks when there is no app in flash */ - bank->num_sectors = bank->size / esp_xtensa_info->sec_sz; - bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (bank->sectors == NULL) { - LOG_ERROR("Failed to alloc mem for sectors!"); - return ERROR_FAIL; - } - for (int i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].offset = i*esp_xtensa_info->sec_sz; - bank->sectors[i].size = esp_xtensa_info->sec_sz; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 0; - } - } - LOG_DEBUG("allocated %d sectors", bank->num_sectors); - esp_xtensa_info->probed = 1; - - return ERROR_OK; -} - -int esp_xtensa_auto_probe(struct flash_bank *bank) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - if (esp_xtensa_info->probed) - return ERROR_OK; - return esp_xtensa_probe(bank); -} - -static int esp_xtensa_flash_bp_op_state_init(struct target *target, - struct xtensa_algo_run_data *run, - struct esp_xtensa_flash_bp_op_state *state) -{ - /* aloocate target buffer for temp storage of flash sections contents when modifying - * instruction */ - LOG_DEBUG("SEC_SIZE %d", state->esp_xtensa_info->sec_sz); - int ret = target_alloc_alt_working_area(target, - 2*(state->esp_xtensa_info->sec_sz), - &state->target_buf); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to alloc target buffer for insn sectors!"); - return ret; - } - buf_set_u32(run->priv.stub.reg_params[XTENSA_STUB_ARGS_FUNC_START+3].value, - 0, - 32, - state->target_buf->address); /* - * insn - * sectors */ - - return ERROR_OK; -} - -static void esp_xtensa_flash_bp_op_state_cleanup(struct target *target, - struct xtensa_algo_run_data *run, - struct esp_xtensa_flash_bp_op_state *state) -{ - if (!state->target_buf) - return; - target_free_alt_working_area(target, state->target_buf); -} - -int esp_xtensa_flash_breakpoint_add(struct target *target, - struct breakpoint *breakpoint, - struct esp_xtensa_flash_breakpoint *sw_bp) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info; - struct xtensa_algo_run_data run; - struct flash_bank *bank; - struct esp_xtensa_flash_bp_op_state op_state; - struct mem_param mp; - struct xtensa_algo_image flasher_image; - - /* flash belongs to root target, so we need to find flash using it instead of core - * sub-target */ - int ret = get_flash_bank_by_addr(target, breakpoint->address, true, &bank); - if (ret != ERROR_OK) { - LOG_ERROR("%s: Failed to get flash bank (%d)!", target_name(target), ret); - return ret; - } - - /* can set set breakpoints in mapped app regions only */ - if (!BANK_SUBNAME(bank, ".irom")) { - LOG_ERROR("%s: Can not set BP outside of IROM (BP addr " TARGET_ADDR_FMT ")!", - target_name(target), - breakpoint->address); - return ERROR_FAIL; - } - - esp_xtensa_info = bank->driver_priv; - - op_state.esp_xtensa_info = esp_xtensa_info; - LOG_DEBUG("SEC_SIZE %d", esp_xtensa_info->sec_sz); - memset(&run, 0, sizeof(run)); - run.stack_size = 1300; - run.usr_func_arg = &op_state; - run.usr_func_init = (xtensa_algo_usr_func_init_t)esp_xtensa_flash_bp_op_state_init; - run.usr_func_done = (xtensa_algo_usr_func_done_t)esp_xtensa_flash_bp_op_state_cleanup; - - sw_bp->data.oocd_bp = breakpoint; - sw_bp->priv = bank; - - ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - init_mem_param(&mp, 2 /*2nd usr arg*/, 3 /*size in bytes*/, PARAM_IN); - run.mem_args.params = ∓ - run.mem_args.count = 1; - uint32_t bp_flash_addr = esp_xtensa_info->hw_flash_base + - (breakpoint->address - bank->base); - ret = esp_xtensa_info->run_func_image(target, - &run, - &flasher_image, - 4 /*args num*/, - ESP_XTENSA_STUB_CMD_FLASH_BP_SET /*cmd*/, - bp_flash_addr /*bp_addr*/, - 0 /*address to store insn*/, - 0 /*address to store insn sectors*/); - if (ret != ERROR_OK) { - LOG_ERROR("%s: Failed to run flasher stub (%d)!", target_name(target), ret); - destroy_mem_param(&mp); - sw_bp->data.oocd_bp = NULL; - return ret; - } - if (run.ret_code == 0) { - LOG_ERROR("%s: Failed to set bp (%d)!", target_name(target), run.ret_code); - destroy_mem_param(&mp); - sw_bp->data.oocd_bp = NULL; - return ERROR_FAIL; - } - sw_bp->data.insn_sz = run.ret_code; - memcpy(sw_bp->data.insn, mp.value, 3); - destroy_mem_param(&mp); - LOG_DEBUG( - "%s: Placed flash SW breakpoint at " TARGET_ADDR_FMT - ", insn [%02x %02x %02x] %d bytes", - target_name(target), - breakpoint->address, - sw_bp->data.insn[0], - sw_bp->data.insn[1], - sw_bp->data.insn[2], - sw_bp->data.insn_sz); - - return ERROR_OK; -} - -int esp_xtensa_flash_breakpoint_remove(struct target *target, - struct esp_xtensa_flash_breakpoint *sw_bp) -{ - struct flash_bank *bank = (struct flash_bank *)(sw_bp->priv); - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct esp_xtensa_flash_bp_op_state op_state; - struct mem_param mp; - struct xtensa_algo_image flasher_image; - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - op_state.esp_xtensa_info = esp_xtensa_info; - memset(&run, 0, sizeof(run)); - run.stack_size = 1300; - run.usr_func_arg = &op_state; - run.usr_func_init = (xtensa_algo_usr_func_init_t)esp_xtensa_flash_bp_op_state_init; - run.usr_func_done = (xtensa_algo_usr_func_done_t)esp_xtensa_flash_bp_op_state_cleanup; - - init_mem_param(&mp, 2 /*2nd usr arg*/, 3 /*size in bytes*/, PARAM_OUT); - memcpy(mp.value, sw_bp->data.insn, 3); - run.mem_args.params = ∓ - run.mem_args.count = 1; - - uint32_t bp_flash_addr = esp_xtensa_info->hw_flash_base + - (sw_bp->data.oocd_bp->address - bank->base); - LOG_DEBUG( - "%s: Remove flash SW breakpoint at " TARGET_ADDR_FMT - ", insn [%02x %02x %02x] %d bytes", - target_name(target), - sw_bp->data.oocd_bp->address, - sw_bp->data.insn[0], - sw_bp->data.insn[1], - sw_bp->data.insn[2], - sw_bp->data.insn_sz); - ret = esp_xtensa_info->run_func_image(target, - &run, - &flasher_image, - 4 /*args num*/, - ESP_XTENSA_STUB_CMD_FLASH_BP_CLEAR /*cmd*/, - bp_flash_addr /*bp_addr*/, - 0 /*address with insn*/, - 0 /*address to store insn sectors*/); - destroy_mem_param(&mp); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to clear bp (%d)!", run.ret_code); - return ERROR_FAIL; - } - - sw_bp->data.oocd_bp = NULL; - return ret; -} - -static int esp_xtensa_flash_calc_hash(struct flash_bank *bank, uint8_t *hash, - uint32_t offset, uint32_t count) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct xtensa_algo_image flasher_image; - - if (offset & 0x3UL) { - LOG_ERROR("Unaligned offset!"); - return ERROR_FAIL; - } - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1024 + ESP_XTENSA_STUB_RDWR_BUFF_SIZE; - - struct mem_param mp; - init_mem_param(&mp, - 3 /*2nd usr arg*/, - 32 /*sha256 hash size in bytes*/, - PARAM_IN); - run.mem_args.params = ∓ - run.mem_args.count = 1; - - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 4 /*args num*/, - ESP_XTENSA_STUB_CMD_FLASH_CALC_HASH /*cmd*/, - esp_xtensa_info->hw_flash_base + offset, - count, - 0 /*address to store hash value*/); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - destroy_mem_param(&mp); - return ret; - } - if (run.ret_code != ESP_XTENSA_STUB_ERR_OK) { - LOG_ERROR("Failed to get hash value (%d)!", run.ret_code); - ret = ERROR_FAIL; - } else - memcpy(hash, mp.value, 32); - destroy_mem_param(&mp); - return ret; -} - -static int esp_xtensa_boost_clock_freq(struct flash_bank *bank, int boost) -{ - struct esp_xtensa_flash_bank *esp_xtensa_info = bank->driver_priv; - struct xtensa_algo_run_data run; - struct xtensa_algo_image flasher_image; - int new_cpu_freq = -1; /* set to max level */ - - int ret = esp_xtensa_flasher_image_init(&flasher_image, esp_xtensa_info->get_stub(bank)); - if (ret != ERROR_OK) - return ret; - - /* restore */ - if (boost == 0) - new_cpu_freq = esp_xtensa_info->old_cpu_freq; - - memset(&run, 0, sizeof(run)); - run.stack_size = 1024; - ret = esp_xtensa_info->run_func_image(bank->target, - &run, - &flasher_image, - 2, - ESP_XTENSA_STUB_CMD_CLOCK_CONFIGURE, - new_cpu_freq); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to run flasher stub (%d)!", ret); - return ERROR_FAIL; - } - esp_xtensa_info->old_cpu_freq = run.ret_code; - LOG_DEBUG("%s old_freq (%d) new_freq (%d)", - __func__, - esp_xtensa_info->old_cpu_freq, - new_cpu_freq); - return ERROR_OK; -} - -static int esp_xtensa_target_to_flash_bank(struct target *target, - struct flash_bank **bank, char *bank_name_suffix, bool probe) -{ - if (target == NULL || bank == NULL) - return ERROR_FAIL; - - char bank_name[64]; - int retval = snprintf(bank_name, - sizeof(bank_name), - "%s.%s", - target_name(target), - bank_name_suffix); - if (retval == sizeof(bank_name)) { - LOG_ERROR("Failed to build bank name string!"); - return ERROR_FAIL; - } - if (probe) { - retval = get_flash_bank_by_name(bank_name, bank); - if (retval != ERROR_OK || bank == NULL) { - LOG_ERROR("Failed to find bank '%s'!", bank_name); - return retval; - } - } else {/* noprobe */ - *bank = get_flash_bank_by_name_noprobe(bank_name); - if (*bank == NULL) { - LOG_ERROR("Failed to find bank '%s'!", bank_name); - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int esp_xtensa_appimage_flash_base_update(struct target *target, - char *bank_name_suffix, - uint32_t appimage_flash_base) -{ - struct flash_bank *bank; - struct esp_xtensa_flash_bank *esp_xtensa_info; - - int retval = esp_xtensa_target_to_flash_bank(target, &bank, bank_name_suffix, false); - if (retval != ERROR_OK) - return ERROR_FAIL; - - esp_xtensa_info = (struct esp_xtensa_flash_bank *)bank->driver_priv; - esp_xtensa_info->probed = 0; - esp_xtensa_info->appimage_flash_base = appimage_flash_base; - retval = bank->driver->auto_probe(bank); - return retval; -} - -COMMAND_HELPER(esp_xtensa_cmd_appimage_flashoff_do, struct target *target) -{ - if (CMD_ARGC != 1) { - command_print(CMD, "Flash offset not specified!"); - return ERROR_FAIL; - } - - /* update app image base */ - uint32_t appimage_flash_base = strtoul(CMD_ARGV[0], NULL, 16); - - int ret = esp_xtensa_appimage_flash_base_update(target, "irom", appimage_flash_base); - if (ret != ERROR_OK) - return ret; - ret = esp_xtensa_appimage_flash_base_update(target, "drom", appimage_flash_base); - if (ret != ERROR_OK) - return ret; - - return ERROR_OK; -} - -COMMAND_HANDLER(esp_xtensa_cmd_appimage_flashoff) -{ - return CALL_COMMAND_HANDLER(esp_xtensa_cmd_appimage_flashoff_do, - get_current_target(CMD_CTX)); -} - -static int esp_xtensa_set_compression(struct target *target, - char *bank_name_suffix, - int compression) -{ - struct flash_bank *bank; - struct esp_xtensa_flash_bank *esp_xtensa_info; - - int retval = esp_xtensa_target_to_flash_bank(target, &bank, bank_name_suffix, true); - if (retval != ERROR_OK) - return ERROR_FAIL; - - esp_xtensa_info = (struct esp_xtensa_flash_bank *)bank->driver_priv; - esp_xtensa_info->compression = compression; - return ERROR_OK; -} - -COMMAND_HELPER(esp_xtensa_cmd_set_compression, struct target *target) -{ - if (CMD_ARGC != 1) { - command_print(CMD, "Compression not specified!"); - return ERROR_FAIL; - } - - int compression = 0; - - if (0 == strcmp("on", CMD_ARGV[0])) { - LOG_DEBUG("Flash compressed upload is on"); - compression = 1; - } else if (0 == strcmp("off", CMD_ARGV[0])) { - LOG_DEBUG("Flash compressed upload is off"); - compression = 0; - } else { - LOG_DEBUG("unknown flag"); - return ERROR_FAIL; - } - - return esp_xtensa_set_compression(target, "flash", compression); -} - -COMMAND_HANDLER(esp_xtensa_cmd_compression) -{ - return CALL_COMMAND_HANDLER(esp_xtensa_cmd_set_compression, - get_current_target(CMD_CTX)); -} - -static int esp_xtensa_verify_bank_hash(struct target *target, - uint32_t offset, - const char *file_name) -{ - uint8_t file_hash[TC_SHA256_DIGEST_SIZE], target_hash[TC_SHA256_DIGEST_SIZE]; - uint8_t *buffer_file; - struct fileio *fileio; - size_t filesize, length, read_cnt; - int differ, retval; - struct flash_bank *bank; - - retval = esp_xtensa_target_to_flash_bank(target, &bank, "flash", true); - if (retval != ERROR_OK) - return ERROR_FAIL; - - if (offset > bank->size) { - LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", - offset); - return ERROR_COMMAND_ARGUMENT_INVALID; - } - - retval = fileio_open(&fileio, file_name, FILEIO_READ, FILEIO_BINARY); - if (retval != ERROR_OK) { - LOG_ERROR("Could not open file"); - return retval; - } - - retval = fileio_size(fileio, &filesize); - if (retval != ERROR_OK) { - fileio_close(fileio); - return retval; - } - - length = MIN(filesize, bank->size - offset); - - if (!length) { - LOG_INFO("Nothing to compare with flash bank"); - fileio_close(fileio); - return ERROR_OK; - } - - if (length != filesize) - LOG_WARNING("File content exceeds flash bank size. Only comparing the " - "first %zu bytes of the file", length); - - LOG_DEBUG("File size: %zu bank_size: %u offset: %u", - filesize, bank->size, offset); - - buffer_file = malloc(length); - if (buffer_file == NULL) { - LOG_ERROR("Out of memory"); - fileio_close(fileio); - return ERROR_FAIL; - } - - retval = fileio_read(fileio, length, buffer_file, &read_cnt); - fileio_close(fileio); - if (retval != ERROR_OK || read_cnt != length) { - LOG_ERROR("File read failure"); - free(buffer_file); - return retval; - } - - retval = esp_xtensa_calc_hash(buffer_file, length, file_hash); - free(buffer_file); - if (retval != ERROR_OK) { - LOG_ERROR("File sha256 calculation failure"); - return retval; - } - - retval = esp_xtensa_flash_calc_hash(bank, target_hash, offset, length); - if (retval != ERROR_OK) { - LOG_ERROR("Flash sha256 calculation failure"); - return retval; - } - - differ = memcmp(file_hash, target_hash, TC_SHA256_DIGEST_SIZE); - - if (differ) { - LOG_ERROR("**** Verification failure! ****"); - LOG_ERROR("target_hash %x%x%x...%x%x%x", - target_hash[0], target_hash[1], target_hash[2], - target_hash[29], target_hash[30], target_hash[31]); - LOG_ERROR("file_hash: %x%x%x...%x%x%x", - file_hash[0], file_hash[1], file_hash[2], - file_hash[29], file_hash[30], file_hash[31]); - } - - return differ ? ERROR_FAIL : ERROR_OK; -} - -COMMAND_HELPER(esp_xtensa_parse_cmd_verify_bank_hash, struct target *target) -{ - if (CMD_ARGC < 2 || CMD_ARGC > 3) - return ERROR_COMMAND_SYNTAX_ERROR; - - uint32_t offset = 0; - - if (CMD_ARGC > 2) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); - - return esp_xtensa_verify_bank_hash(target, offset, CMD_ARGV[1]); -} - -COMMAND_HANDLER(esp_xtensa_cmd_verify_bank_hash) -{ - return CALL_COMMAND_HANDLER(esp_xtensa_parse_cmd_verify_bank_hash, - get_current_target(CMD_CTX)); -} - -COMMAND_HELPER(esp_xtensa_parse_cmd_clock_boost, struct target *target) -{ - if (CMD_ARGC != 1) { - command_print(CMD, "Clock boost flag not specified!"); - return ERROR_FAIL; - } - - int boost = 0; - - if (0 == strcmp("on", CMD_ARGV[0])) { - LOG_DEBUG("Clock boost is on"); - boost = 1; - } else if (0 == strcmp("off", CMD_ARGV[0])) { - LOG_DEBUG("Clock boost is off"); - boost = 0; - } else { - LOG_DEBUG("unknown flag"); - return ERROR_FAIL; - } - - struct flash_bank *bank; - int retval = esp_xtensa_target_to_flash_bank(target, &bank, "flash", true); - if (retval != ERROR_OK) - return ERROR_FAIL; - - return esp_xtensa_boost_clock_freq(bank, boost); -} - -COMMAND_HANDLER(esp_xtensa_cmd_clock_boost) -{ - return CALL_COMMAND_HANDLER(esp_xtensa_parse_cmd_clock_boost, - get_current_target(CMD_CTX)); -} - -const struct command_registration esp_xtensa_exec_flash_command_handlers[] = { - { - .name = "appimage_offset", - .handler = esp_xtensa_cmd_appimage_flashoff, - .mode = COMMAND_ANY, - .help = - "Set offset of application image in flash. Use -1 to debug the first application image from partition table.", - .usage = "offset", - }, - { - .name = "compression", - .handler = esp_xtensa_cmd_compression, - .mode = COMMAND_ANY, - .help = - "Set compression flag", - .usage = "['on'|'off']", - }, - { - .name = "verify_bank_hash", - .handler = esp_xtensa_cmd_verify_bank_hash, - .mode = COMMAND_ANY, - .help = "Perform a comparison between the file and the contents of the " - "flash bank using SHA256 hash values. Allow optional offset from beginning of the bank " - "(defaults to zero).", - .usage = "bank_id filename [offset]", - }, - { - .name = "flash_stub_clock_boost", - .handler = esp_xtensa_cmd_clock_boost, - .mode = COMMAND_ANY, - .help = - "Set cpu clock freq to the max level. Use 'off' to restore the clock speed", - .usage = "['on'|'off']", - }, - COMMAND_REGISTRATION_DONE -}; diff --git a/src/flash/nor/esp_xtensa.h b/src/flash/nor/esp_xtensa.h index 561b99d642..ab5ffb09a0 100644 --- a/src/flash/nor/esp_xtensa.h +++ b/src/flash/nor/esp_xtensa.h @@ -22,74 +22,20 @@ #ifndef FLASH_ESP_XTENSA_H #define FLASH_ESP_XTENSA_H -#include -#include -#include -#include -#include +#include "esp_flash.h" -/* ESP xtensa flash data. +/* ESP Xtensa flash data. It should be the first member of flash data structs for concrete chips. For example see ESP32 flash driver implementation. */ struct esp_xtensa_flash_bank { - int probed; - /* Sector size */ - uint32_t sec_sz; - /* Base address of the bank in the flash, 0 - for HW flash bank, non-zero for special - * IROM/DROM fake banks */ - /* Those fake banks are necessary for generating proper memory map for GDB and using flash - * breakpoints */ - uint32_t hw_flash_base; - /* Offset of the application image in the HW flash bank */ - uint32_t appimage_flash_base; - const struct esp_xtensa_flasher_stub_config *(*get_stub)(struct flash_bank *bank); - /* function to run algorithm on Xtensa target */ - int (*run_func_image)(struct target *target, struct xtensa_algo_run_data *run, - struct xtensa_algo_image *image, uint32_t num_args, ...); - bool (*is_irom_address)(target_addr_t addr); - bool (*is_drom_address)(target_addr_t addr); - /* Upload compressed or uncompressed image */ - int compression; - /* Stub cpu frequency before boost */ - int old_cpu_freq; + struct esp_flash_bank esp; }; -struct esp_xtensa_flasher_stub_config { - const uint8_t *code; - uint32_t code_sz; - const uint8_t *data; - uint32_t data_sz; - target_addr_t entry_addr; - uint32_t bss_sz; -}; - -extern const struct command_registration esp_xtensa_exec_flash_command_handlers[]; - -int esp_xtensa_flash_init(struct esp_xtensa_flash_bank *esp_xtensa_info, uint32_t sec_sz, - int (*run_func_image)(struct target *target, struct xtensa_algo_run_data *run, - struct xtensa_algo_image *image, uint32_t num_args, ...), +int esp_xtensa_flash_init(struct esp_xtensa_flash_bank *esp_info, uint32_t sec_sz, + int (*run_func_image)(struct target *target, struct algorithm_run_data *run, + uint32_t num_args, ...), bool (*is_irom_address)(target_addr_t addr), bool (*is_drom_address)(target_addr_t addr), - const struct esp_xtensa_flasher_stub_config *(*get_stub)(struct flash_bank *bank)); -int esp_xtensa_protect(struct flash_bank *bank, int set, int first, int last); -int esp_xtensa_protect_check(struct flash_bank *bank); -int esp_xtensa_blank_check(struct flash_bank *bank); -int esp_xtensa_erase(struct flash_bank *bank, int first, int last); -int esp_xtensa_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count); -int esp_xtensa_read(struct flash_bank *bank, uint8_t *buffer, - uint32_t offset, uint32_t count); -int esp_xtensa_probe(struct flash_bank *bank); -int esp_xtensa_auto_probe(struct flash_bank *bank); -int esp_xtensa_flash_breakpoint_add(struct target *target, - struct breakpoint *breakpoint, - struct esp_xtensa_flash_breakpoint *sw_bp); -int esp_xtensa_flash_breakpoint_remove(struct target *target, - struct esp_xtensa_flash_breakpoint *sw_bp); - -COMMAND_HELPER(esp_xtensa_cmd_appimage_flashoff_do, struct target *target); -COMMAND_HELPER(esp_xtensa_cmd_set_compression, struct target *target); -COMMAND_HELPER(esp_xtensa_parse_cmd_verify_bank_hash, struct target *target); -COMMAND_HELPER(esp_xtensa_parse_cmd_clock_boost, struct target *target); + const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank)); #endif /*FLASH_ESP_XTENSA_H*/ diff --git a/src/target/esp32.c b/src/target/esp32.c index 76a9d72047..22f6000aba 100644 --- a/src/target/esp32.c +++ b/src/target/esp32.c @@ -587,8 +587,8 @@ static const struct xtensa_power_ops esp32_pwr_ops = { }; static const struct esp_xtensa_flash_breakpoint_ops esp32_flash_brp_ops = { - .breakpoint_add = esp_xtensa_flash_breakpoint_add, - .breakpoint_remove = esp_xtensa_flash_breakpoint_remove + .breakpoint_add = esp_flash_breakpoint_add, + .breakpoint_remove = esp_flash_breakpoint_remove }; static const struct esp_xtensa_smp_chip_ops esp32_chip_ops = { diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 67c70b4c81..d319bc140e 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -120,7 +120,7 @@ int esp_riscv_semihosting(struct target *target) esp_riscv->semi_ops->prepare(target); if (semihosting->op == ESP_RISCV_APPTRACE_SYSNR) { - res = esp_riscv_apptrace_info_init(target, semihosting->param); + res = esp_riscv_apptrace_info_init(target, semihosting->param, NULL); if (res != ERROR_OK) return res; } else diff --git a/src/target/esp32c3.h b/src/target/esp32c3.h index 597dd8a614..51f9859eb1 100644 --- a/src/target/esp32c3.h +++ b/src/target/esp32c3.h @@ -23,6 +23,11 @@ #include "esp_riscv.h" +#define ESP32C3_DROM_LOW 0x3C000000 +#define ESP32C3_DROM_HIGH 0x3C800000 +#define ESP32C3_IROM_LOW 0x42000000 +#define ESP32C3_IROM_HIGH 0x42800000 + struct esp32c3_common { struct esp_riscv_common esp_riscv; bool was_reset; diff --git a/src/target/esp32s2.c b/src/target/esp32s2.c index 7b95f2983f..3832463c58 100644 --- a/src/target/esp32s2.c +++ b/src/target/esp32s2.c @@ -687,8 +687,8 @@ static const struct xtensa_power_ops esp32s2_pwr_ops = { }; static const struct esp_xtensa_flash_breakpoint_ops esp32s2_spec_brp_ops = { - .breakpoint_add = esp_xtensa_flash_breakpoint_add, - .breakpoint_remove = esp_xtensa_flash_breakpoint_remove + .breakpoint_add = esp_flash_breakpoint_add, + .breakpoint_remove = esp_flash_breakpoint_remove }; static const struct esp_semihost_ops esp32s2_semihost_ops = { diff --git a/src/target/esp32s3.c b/src/target/esp32s3.c index ed75a6df3e..91ad9e46e3 100644 --- a/src/target/esp32s3.c +++ b/src/target/esp32s3.c @@ -593,8 +593,8 @@ static const struct xtensa_power_ops esp32s3_pwr_ops = { }; static const struct esp_xtensa_flash_breakpoint_ops esp32s3_flash_brp_ops = { - .breakpoint_add = esp_xtensa_flash_breakpoint_add, - .breakpoint_remove = esp_xtensa_flash_breakpoint_remove + .breakpoint_add = esp_flash_breakpoint_add, + .breakpoint_remove = esp_flash_breakpoint_remove }; static const struct esp_xtensa_smp_chip_ops esp32s3_chip_ops = { diff --git a/src/target/esp_riscv_apptrace.c b/src/target/esp_riscv_apptrace.c index c9533d6dde..770d4eed83 100644 --- a/src/target/esp_riscv_apptrace.c +++ b/src/target/esp_riscv_apptrace.c @@ -49,26 +49,7 @@ struct esp_apptrace_riscv_ctrl_block { uint32_t mem_blocks_cfg_addr; /* 4 bytes for target pointer */ }; -static int esp_riscv_apptrace_data_len_read(struct target *target, - uint32_t *block_id, - uint32_t *len); -static int esp_riscv_apptrace_data_read(struct target *target, - uint32_t size, - uint8_t *buffer, - uint32_t block_id, - bool ack); -static int esp_riscv_apptrace_ctrl_reg_write(struct target *target, - uint32_t block_id, - uint32_t len, - bool conn, - bool data); -static int esp_riscv_apptrace_ctrl_reg_read(struct target *target, - uint32_t *block_id, - uint32_t *len, - bool *conn); static int esp_riscv_apptrace_status_reg_read(struct target *target, uint32_t *stat); -static uint32_t esp_riscv_apptrace_block_max_size_get(struct target *target); -static uint32_t esp_riscv_apptrace_usr_block_max_size_get(struct target *target); static int esp_riscv_apptrace_buffs_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], @@ -92,7 +73,9 @@ struct esp32_apptrace_hw esp_riscv_apptrace_hw = { }; -int esp_riscv_apptrace_info_init(struct target *target, target_addr_t ctrl_addr) +int esp_riscv_apptrace_info_init(struct target *target, + target_addr_t ctrl_addr, + target_addr_t *old_ctrl_addr) { struct esp_riscv_common *esp_riscv = target_to_esp_riscv(target); uint32_t mem_cfg_addr; @@ -126,30 +109,42 @@ int esp_riscv_apptrace_info_init(struct target *target, target_addr_t ctrl_addr) LOG_DEBUG("Detected memory blocks: [0] %d bytes @ 0x%x, [1] %d bytes @ 0x%x", esp_riscv->apptrace.mem_blocks[0].sz, esp_riscv->apptrace.mem_blocks[0].start, esp_riscv->apptrace.mem_blocks[1].sz, esp_riscv->apptrace.mem_blocks[1].start); + + if (old_ctrl_addr) + *old_ctrl_addr = esp_riscv->apptrace.ctrl_addr; esp_riscv->apptrace.ctrl_addr = ctrl_addr; return ERROR_OK; } -static uint32_t esp_riscv_apptrace_block_max_size_get(struct target *target) +uint32_t esp_riscv_apptrace_block_max_size_get(struct target *target) { struct esp_riscv_common *esp_riscv = target_to_esp_riscv(target); return esp_riscv->apptrace.mem_blocks[0].sz; /* assume blocks are of equal size */ } -static uint32_t esp_riscv_apptrace_usr_block_max_size_get(struct target *target) +uint32_t esp_riscv_apptrace_usr_block_max_size_get(struct target *target) { return (esp_riscv_apptrace_block_max_size_get(target) - sizeof(struct esp_apptrace_host2target_hdr)); } -static int esp_riscv_apptrace_data_len_read(struct target *target, +int esp_riscv_apptrace_usr_block_write(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size) +{ + return esp_apptrace_usr_block_write(&esp_riscv_apptrace_hw, + target, block_id, data, size); +} + +int esp_riscv_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len) { return esp_riscv_apptrace_ctrl_reg_read(target, block_id, len, NULL); } -static int esp_riscv_apptrace_data_read(struct target *target, +int esp_riscv_apptrace_data_read(struct target *target, uint32_t size, uint8_t *buffer, uint32_t block_id, @@ -173,7 +168,7 @@ static int esp_riscv_apptrace_data_read(struct target *target, return res; } -static int esp_riscv_apptrace_ctrl_reg_read(struct target *target, +int esp_riscv_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn) @@ -197,7 +192,7 @@ static int esp_riscv_apptrace_ctrl_reg_read(struct target *target, return ERROR_OK; } -static int esp_riscv_apptrace_ctrl_reg_write(struct target *target, +int esp_riscv_apptrace_ctrl_reg_write(struct target *target, uint32_t block_id, uint32_t len, bool conn, diff --git a/src/target/esp_riscv_apptrace.h b/src/target/esp_riscv_apptrace.h index c528ee92f1..6f9446cd2d 100644 --- a/src/target/esp_riscv_apptrace.h +++ b/src/target/esp_riscv_apptrace.h @@ -33,8 +33,33 @@ struct esp_riscv_apptrace_info { struct esp_riscv_apptrace_mem_block mem_blocks[2]; }; -int esp_riscv_apptrace_info_init(struct target *target, target_addr_t ctrl_addr); - extern struct esp32_apptrace_hw esp_riscv_apptrace_hw; +int esp_riscv_apptrace_info_init(struct target *target, + target_addr_t ctrl_addr, + target_addr_t *old_ctrl_addr); +int esp_riscv_apptrace_data_len_read(struct target *target, + uint32_t *block_id, + uint32_t *len); +int esp_riscv_apptrace_data_read(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack); +int esp_riscv_apptrace_ctrl_reg_read(struct target *target, + uint32_t *block_id, + uint32_t *len, + bool *conn); +int esp_riscv_apptrace_ctrl_reg_write(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data); +uint32_t esp_riscv_apptrace_block_max_size_get(struct target *target); +uint32_t esp_riscv_apptrace_usr_block_max_size_get(struct target *target); +int esp_riscv_apptrace_usr_block_write(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size); + #endif /*ESP_RISCV_APPTRACE_H__*/ diff --git a/src/target/esp_xtensa.c b/src/target/esp_xtensa.c index 51e8656f19..1c2bc365d1 100644 --- a/src/target/esp_xtensa.c +++ b/src/target/esp_xtensa.c @@ -75,9 +75,9 @@ static int esp_xtensa_flash_breakpoints_clear(struct target *target) for (size_t slot = 0; slot < ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM; slot++) { - struct esp_xtensa_flash_breakpoint *flash_bp = + struct esp_flash_breakpoint *flash_bp = &esp_xtensa->flash_brps[slot]; - if (flash_bp->data.oocd_bp != NULL) { + if (flash_bp->oocd_bp != NULL) { int ret = esp_xtensa->flash_brps_ops->breakpoint_remove( target, flash_bp); @@ -86,7 +86,7 @@ static int esp_xtensa_flash_breakpoints_clear(struct target *target) "%s: Failed to remove SW flash BP @ " TARGET_ADDR_FMT " (%d)!", target_name(target), - flash_bp->data.oocd_bp->address, + flash_bp->oocd_bp->address, ret); return ret; } @@ -95,7 +95,7 @@ static int esp_xtensa_flash_breakpoints_clear(struct target *target) memset(esp_xtensa->flash_brps, 0, ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM* - sizeof(struct esp_xtensa_flash_breakpoint)); + sizeof(struct esp_flash_breakpoint)); return ERROR_OK; } @@ -175,7 +175,7 @@ int esp_xtensa_init_arch_info(struct target *target, esp_xtensa->flash_brps_ops = flash_brps_ops; esp_xtensa->flash_brps = calloc(ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM, - sizeof(struct esp_xtensa_flash_breakpoint)); + sizeof(struct esp_flash_breakpoint)); if (esp_xtensa->flash_brps == NULL) return ERROR_FAIL; esp_xtensa->apptrace.hw = &esp_xtensa_apptrace_hw; @@ -300,7 +300,7 @@ static bool esp_xtensa_flash_breakpoint_exists(struct target *target, struct bre { struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); for (uint32_t slot = 0; slot < ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM; slot++) { - struct breakpoint *curr = esp_xtensa->flash_brps[slot].data.oocd_bp; + struct breakpoint *curr = esp_xtensa->flash_brps[slot].oocd_bp; if (curr != NULL && curr->address == breakpoint->address) return true; } @@ -323,8 +323,8 @@ static int esp_xtensa_flash_breakpoint_add(struct target *target, struct breakpo } for (slot = 0; slot < ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM; slot++) { - if (esp_xtensa->flash_brps[slot].data.oocd_bp == NULL || - esp_xtensa->flash_brps[slot].data.oocd_bp == breakpoint) + if (esp_xtensa->flash_brps[slot].oocd_bp == NULL || + esp_xtensa->flash_brps[slot].oocd_bp == breakpoint) break; } if (slot == ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM) { @@ -350,8 +350,8 @@ static int esp_xtensa_flash_breakpoint_remove(struct target *target, uint32_t slot; for (slot = 0; slot < ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM; slot++) { - if (esp_xtensa->flash_brps[slot].data.oocd_bp != NULL && - esp_xtensa->flash_brps[slot].data.oocd_bp == breakpoint) + if (esp_xtensa->flash_brps[slot].oocd_bp != NULL && + esp_xtensa->flash_brps[slot].oocd_bp == breakpoint) break; } if (slot == ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM) { diff --git a/src/target/esp_xtensa.h b/src/target/esp_xtensa.h index 0986796d1e..582b325568 100644 --- a/src/target/esp_xtensa.h +++ b/src/target/esp_xtensa.h @@ -28,20 +28,16 @@ #include "xtensa.h" #include "esp_xtensa_apptrace.h" #include "esp_xtensa_semihosting.h" +#include "flash/nor/esp_flash.h" #define ESP_XTENSA_FLASH_BREAKPOINTS_MAX_NUM 32 -struct esp_xtensa_flash_breakpoint { - struct xtensa_sw_breakpoint data; - void *priv; -}; - struct esp_xtensa_flash_breakpoint_ops { int (*breakpoint_add)(struct target *target, struct breakpoint *breakpoint, - struct esp_xtensa_flash_breakpoint *spec_bp); + struct esp_flash_breakpoint *bp); int (*breakpoint_remove)(struct target *target, - struct esp_xtensa_flash_breakpoint *spec_bp); + struct esp_flash_breakpoint *bp); }; struct esp_xtensa_semihost_data { @@ -55,7 +51,7 @@ struct esp_xtensa_common { struct xtensa xtensa; struct esp_dbg_stubs dbg_stubs; const struct esp_xtensa_flash_breakpoint_ops *flash_brps_ops; - struct esp_xtensa_flash_breakpoint *flash_brps; + struct esp_flash_breakpoint *flash_brps; struct esp_xtensa_semihost_data semihost; struct esp_xtensa_apptrace_info apptrace; const struct algorithm_hw *algo_hw; diff --git a/src/target/esp_xtensa_apptrace.c b/src/target/esp_xtensa_apptrace.c index f1631c2f84..5ed844b1d9 100644 --- a/src/target/esp_xtensa_apptrace.c +++ b/src/target/esp_xtensa_apptrace.c @@ -296,6 +296,15 @@ int esp_xtensa_apptrace_data_len_read(struct target *target, return esp_xtensa_apptrace_ctrl_reg_read(target, block_id, len, NULL); } +int esp_xtensa_apptrace_usr_block_write(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size) +{ + return esp_apptrace_usr_block_write(&esp_xtensa_apptrace_hw, + target, block_id, data, size); +} + static int esp_xtensa_apptrace_data_reverse_read(struct xtensa *xtensa, uint32_t size, uint8_t *buffer, diff --git a/src/target/esp_xtensa_apptrace.h b/src/target/esp_xtensa_apptrace.h index 9cc3f0f8b1..ad239e7a43 100644 --- a/src/target/esp_xtensa_apptrace.h +++ b/src/target/esp_xtensa_apptrace.h @@ -49,11 +49,9 @@ int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat); int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat); uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target); uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target); -#define esp_xtensa_apptrace_usr_block_write(target, block_id, data, \ - size) esp_apptrace_usr_block_write(&esp_xtensa_apptrace_hw, \ - target, \ - block_id, \ - data, \ - size) +int esp_xtensa_apptrace_usr_block_write(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size); #endif /*ESP_XTENSA_APPTRACE_H__*/ diff --git a/src/target/esp_xtensa_smp.c b/src/target/esp_xtensa_smp.c index 689317d605..00b1bdada5 100644 --- a/src/target/esp_xtensa_smp.c +++ b/src/target/esp_xtensa_smp.c @@ -508,7 +508,7 @@ int esp_xtensa_smp_run_func_image(struct target *target, } int esp_xtensa_smp_run_onboard_func(struct target *target, - struct xtensa_algo_run_data *run, + struct algorithm_run_data *run, uint32_t func_addr, uint32_t num_args, ...) @@ -537,7 +537,7 @@ int esp_xtensa_smp_run_onboard_func(struct target *target, run_target = target; va_start(ap, num_args); - res = xtensa_run_onboard_func_va(run_target, run, func_addr, num_args, ap); + res = algorithm_run_onboard_func_va(run_target, run, func_addr, num_args, ap); va_end(ap); if (target->smp) { diff --git a/src/target/esp_xtensa_smp.h b/src/target/esp_xtensa_smp.h index 2aeb17136f..16898c652d 100644 --- a/src/target/esp_xtensa_smp.h +++ b/src/target/esp_xtensa_smp.h @@ -68,7 +68,7 @@ int esp_xtensa_smp_run_func_image(struct target *target, uint32_t num_args, ...); int esp_xtensa_smp_run_onboard_func(struct target *target, - struct xtensa_algo_run_data *run, + struct algorithm_run_data *run, uint32_t func_addr, uint32_t num_args, ...); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a97443bb57..4f9692301f 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1545,23 +1545,6 @@ static int riscv_interrupts_disable(struct target *target, uint64_t ie_mask, uin return ERROR_OK; } -static int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus) -{ - riscv_info_t *info = (riscv_info_t *) target->arch_info; - uint8_t mstatus_bytes[8]; - - LOG_DEBUG("Restore Interrupts"); - struct reg *reg_mstatus = register_get_by_name(target->reg_cache, - "mstatus", 1); - if (!reg_mstatus) { - LOG_ERROR("Couldn't find mstatus!"); - return ERROR_FAIL; - } - - buf_set_u64(mstatus_bytes, 0, info->xlen[0], old_mstatus); - return reg_mstatus->type->set(reg_mstatus, mstatus_bytes); -} - /* Algorithm must end with a software breakpoint instruction. */ static int riscv_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, diff --git a/tcl/target/esp32c3.cfg b/tcl/target/esp32c3.cfg index e7e5452c50..580447c1a2 100644 --- a/tcl/target/esp32c3.cfg +++ b/tcl/target/esp32c3.cfg @@ -1,9 +1,6 @@ # The ESP32-C3 only supports JTAG. transport select jtag -# TODO: remove when flash support is ready -set ESP_FLASH_SIZE "0" - # Source the ESP common configuration file source [find target/esp_common.cfg] @@ -84,11 +81,19 @@ $_TARGETNAME configure -event examine-end { arm semihosting enable arm semihosting_resexit enable } +$_TARGETNAME configure -event gdb-attach { + # 'reset' is necessary to disable memory protection which might be enabled by bootloader + # 'halt' is necessary to auto-probe flash bank when GDB is connected and generate proper memory map + reset halt +} -configure_esp_workarea $_TARGETNAME 0x4037C000 0x4000 0x3FC80000 0x6000 - -# TODO: Add support -# configure_esp_flash_bank $_TARGETNAME $_TARGETNAME $_FLASH_SIZE +# stub flasher may need a lot of memory in case of compressed writes to flash (~107KB): +# - for apptrace: 2x16KB up buffers + 32KB down buffer +# - for uncompression: 32KB for unzip buffer size + 11KB for inflator data structs +# TODO: In general when up buffers are swapped apptrace copies `host->target` data from new up buffer to down buffer to free space for `target->host` data. +# In case of flash writes we use apptrace transfers in one direction only. So we can avoid copying and re-use up buffer instead of down one. +configure_esp_workarea $_TARGETNAME 0x40380000 0x4000 0x3FC84000 0x20000 +configure_esp_flash_bank $_TARGETNAME $_TARGETNAME $_FLASH_SIZE if { $_FLASH_SIZE == 0 } { gdb_breakpoint_override hard diff --git a/testing/esp/test_bp.py b/testing/esp/test_bp.py index b893c8284c..eda1ebaafc 100644 --- a/testing/esp/test_bp.py +++ b/testing/esp/test_bp.py @@ -163,7 +163,7 @@ def test_bp_and_reconnect(self): def test_bp_in_isr(self): """ - This test checks that the first several breakpoint's hits can be ignored: + This test checks that the breakpoint's are handled in ISR properly: 1) Select appropriate sub-test number on target. 2) Set several breakpoints in ISR code to cover all types of them (HW, SW). 3) Resume target and wait for brekpoints to hit. @@ -201,21 +201,25 @@ def test_wp_simple(self): for e in self.wps: self.add_wp(e, 'rw') cnt = 0 + wp_stop_reason = [dbg.TARGET_STOP_REASON_SIGTRAP, dbg.TARGET_STOP_REASON_WP] for i in range(3): # 'count' read - self.run_to_bp_and_check(dbg.TARGET_STOP_REASON_SIGTRAP, 'blink_task', ['s_count10']) + self.run_to_bp_and_check(wp_stop_reason, 'blink_task', ['s_count10']) var_val = int(self.gdb.data_eval_expr('s_count1')) self.assertEqual(var_val, cnt) # 'count' read - self.run_to_bp_and_check(dbg.TARGET_STOP_REASON_SIGTRAP, 'blink_task', ['s_count11']) + self.run_to_bp_and_check(wp_stop_reason, 'blink_task', ['s_count11']) var_val = int(self.gdb.data_eval_expr('s_count1')) self.assertEqual(var_val, cnt) # 'count' write - self.run_to_bp_and_check(dbg.TARGET_STOP_REASON_SIGTRAP, 'blink_task', ['s_count11']) + self.run_to_bp_and_check(wp_stop_reason, 'blink_task', ['s_count11']) var_val = int(self.gdb.data_eval_expr('s_count1')) self.assertEqual(var_val, cnt) cnt += 1 + # OpenOCD resets eps32c3/esp32s2 on every GDB connect to ensure that memory protection is disabled + # TODO: add check to config file to reset chip only when memory protection is really enabled + @skip_for_chip(['esp32s2', 'esp32c3']) def test_wp_and_reconnect(self): """ This test checks that watchpoints work after GDB re-connection. diff --git a/tools/format-esp.sh b/tools/format-esp.sh index b5d88c2bd9..d7bc9b286d 100755 --- a/tools/format-esp.sh +++ b/tools/format-esp.sh @@ -18,6 +18,7 @@ ./tools/uncrustify1.sh src/target/esp32c3.c ./tools/uncrustify1.sh src/target/esp32_apptrace.c ./tools/uncrustify1.sh src/target/esp32_sysview.c +./tools/uncrustify1.sh src/target/esp.h ./tools/uncrustify1.sh src/target/esp_xtensa.h ./tools/uncrustify1.sh src/target/esp_riscv.h ./tools/uncrustify1.sh src/target/esp_xtensa_apptrace.h @@ -27,10 +28,17 @@ ./tools/uncrustify1.sh src/target/esp32c3.h ./tools/uncrustify1.sh src/target/esp32_apptrace.h ./tools/uncrustify1.sh src/target/esp32_sysview.h +./tools/uncrustify1.sh src/target/riscv/riscv_algorithm.c +./tools/uncrustify1.sh src/target/riscv/riscv_algorithm.h +./tools/uncrustify1.sh src/flash/nor/esp_flash.h +./tools/uncrustify1.sh src/flash/nor/esp_riscv.h ./tools/uncrustify1.sh src/flash/nor/esp_xtensa.h +./tools/uncrustify1.sh src/flash/nor/esp_flash.c +./tools/uncrustify1.sh src/flash/nor/esp_riscv.c ./tools/uncrustify1.sh src/flash/nor/esp_xtensa.c ./tools/uncrustify1.sh src/flash/nor/esp32s2.c ./tools/uncrustify1.sh src/flash/nor/esp32.c +./tools/uncrustify1.sh src/flash/nor/esp32c3.c ./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32/sdkconfig.h ./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32/stub_flasher_chip.h ./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32/stub_flasher_image.h @@ -41,6 +49,12 @@ ./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32_s2/stub_flasher_image.h ./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32_s2/stub_flasher_chip.c ./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32_s2/stub_sha.c +./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32c3/sdkconfig.h +./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.c +./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32c3/stub_flasher_chip.h +./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32c3/stub_flasher_image.h +./tools/uncrustify1.sh contrib/loaders/flash/esp/esp32c3/stub_sha.c +./tools/uncrustify1.sh contrib/loaders/flash/esp/xtensa/stub_xtensa_chips.h ./tools/uncrustify1.sh contrib/loaders/flash/esp/stub_flasher_int.h ./tools/uncrustify1.sh contrib/loaders/flash/esp/stub_flasher.c ./tools/uncrustify1.sh contrib/loaders/flash/esp/stub_flasher.h