This is an automated email from Gerrit. "Erhan Kurubas <erhan.kuru...@espressif.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7764
-- gerrit commit 0d696aae57c8d3b8cac3f15fb648a5662b8c8f4d Author: Erhan Kurubas <erhan.kuru...@espressif.com> Date: Fri Jul 7 15:16:39 2023 +0200 src/flash/nor: add flash driver for Espressif chips. Currently flash write, read, erase, get_mappings, probe and appimage_offset commands are supported. Checkpatch-ignore: MACRO_ARG_REUSE Signed-off-by: Erhan Kurubas <erhan.kuru...@espressif.com> Change-Id: Ic7714b7844ac9ea9ba8061d6743fcfee403acb0d diff --git a/contrib/loaders/flash/espressif/stub_flasher.h b/contrib/loaders/flash/espressif/stub_flasher.h new file mode 100644 index 0000000000..b0ea75af15 --- /dev/null +++ b/contrib/loaders/flash/espressif/stub_flasher.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * ESP xtensa chips flasher stub definitions * + * Copyright (C) 2017-2021 Espressif Systems Ltd. * + ***************************************************************************/ +#ifndef OPENOCD_LOADERS_FLASH_ESP_STUB_FLASHER_H +#define OPENOCD_LOADERS_FLASH_ESP_STUB_FLASHER_H + +#include <stdint.h> + +#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_STUB_ERR_INVALID_PARTITION (-7) +#define ESP_STUB_ERR_INVALID_APP_MAGIC (-8) + +#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_STUB_FLASH_MAPPINGS_MAX_NUM 2 /* IROM, DROM */ + +struct esp_flash_region_mapping { + uint32_t phy_addr; + uint32_t load_addr; + uint32_t size; +}; + +struct esp_flash_mapping { + uint32_t maps_num; + struct esp_flash_region_mapping maps[ESP_STUB_FLASH_MAPPINGS_MAX_NUM]; +}; + +struct esp_flash_stub_flash_write_args { + uint32_t start_addr; + uint32_t size; + uint32_t down_buf_addr; + uint32_t down_buf_size; + uint32_t total_size; /* uncompressed file size */ + uint32_t extra_stack_addr; /* extra stack for compression */ + uint32_t options; /* Write options. e.g. encrypted */ +}; + +/* exported to let openocd know for stack allocation */ +#define ESP_STUB_UNZIP_BUFF_SIZE 32768 +#define ESP_STUB_IFLATOR_SIZE 11000 +#define ESP_STUB_RDWR_BUFF_SIZE 32768 + +/* stub runtime options */ +#define ESP_STUB_FLASH_WR_RAW 0x0 +#define ESP_STUB_FLASH_ENCRYPT_BINARY 0x1 + +#endif /* OPENOCD_LOADERS_FLASH_ESP_STUB_FLASHER_H */ diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 534a7a804e..7b141eb228 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -29,6 +29,8 @@ NOR_DRIVERS = \ %D%/efm32.c \ %D%/em357.c \ %D%/esirisc_flash.c \ + %D%/esp_flash.c \ + %D%/esp_xtensa.c \ %D%/faux.c \ %D%/fespi.c \ %D%/fm3.c \ @@ -88,6 +90,8 @@ NORHEADERS = \ %D%/cc26xx.h \ %D%/cfi.h \ %D%/driver.h \ + %D%/esp_flash.h \ + %D%/esp_xtensa.h \ %D%/imp.h \ %D%/non_cfi.h \ %D%/ocl.h \ diff --git a/src/flash/nor/esp_flash.c b/src/flash/nor/esp_flash.c new file mode 100644 index 0000000000..78c2d8121a --- /dev/null +++ b/src/flash/nor/esp_flash.c @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Generic flash driver for Espressif chips * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +/* + * Overview + * -------- + * Like many other flash drivers this one uses a special binary program (stub) running on the target + * to perform all operations and communicate with the host. Stub has an entry function that accepts + * the 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 the 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 execute the stub, the code and data sections need to be loaded onto the target device. + * This is accomplished using the working area API. In ESP32, the code and data address spaces are separate, + * but the CPU can read and write memory from both the data bus and the instruction bus. + * This means that data written from the data bus can be accessed from the instruction bus. + * However, ESP32 differs from other chips as it maps these buses differently. + * To address this, the load function in the algorithm will make the necessary adjustments. + * It is crucial that both the stub code and data sections are located at the beginning of their respective + * working areas because the stub code is linked as ELF and therefore its position is dependent. + * Hence, allocating target memory for the stub code and data is the first step in this process. + + * Stub Execution + * -------------- + * Special wrapping code is used to enter and exit the stub's main function. It prepares to 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 the target a buffer should be allocated at the 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 uses 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 <helper/binarybuffer.h> +#include <target/register.h> +#include <helper/time_support.h> +#include "contrib/loaders/flash/espressif/stub_flasher.h" +#include "esp_flash.h" + +#define ESP_FLASH_RW_TMO 20000 /* ms */ +#define ESP_FLASH_ERASE_TMO 60000 /* ms */ +#define ESP_FLASH_MAPS_MAX 2 + +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; +}; + +static int esp_algo_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; + algo->image.iram_org = stub_cfg->iram_org; + algo->image.iram_len = stub_cfg->iram_len; + algo->image.dram_org = stub_cfg->dram_org; + algo->image.dram_len = stub_cfg->dram_len; + algo->image.reverse = stub_cfg->reverse; + algo->stub.log_buff_addr = stub_cfg->log_buff_addr; + algo->stub.log_buff_size = stub_cfg->log_buff_size; + 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, + ESP_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=%08llx set=%d", algo->image.image.base_address, algo->image.image.base_address_set); + return ret; +} + +int esp_algo_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 = 0; + esp_info->apptrace_hw = apptrace_hw; + esp_info->stub_hw = stub_hw; + + return ERROR_OK; +} + +int esp_algo_flash_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) +{ + return ERROR_FAIL; +} + +int esp_algo_flash_protect_check(struct flash_bank *bank) +{ + return ERROR_OK; +} + +int esp_algo_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_algo_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*/); + image_close(&run.image.image); + 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 (%" PRId32 ")!", run.ret_code); + ret = ERROR_FAIL; + } else { + for (unsigned 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_algo_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_algo_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); + image_close(&run.image.image); + 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_algo_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_algo_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*/); + image_close(&run.image.image); + 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 (%" PRId32 ")!", 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'."); + else if (run.ret_code == ESP_STUB_ERR_INVALID_PARTITION) + LOG_WARNING("Invalid partition! One of the partition size exceeds the flash chip size!"); + else if (run.ret_code == ESP_STUB_ERR_INVALID_APP_MAGIC) + LOG_WARNING("Invalid magic number in app image!"); + ret = ERROR_FAIL; + } else { + memcpy(flash_map, mp.value, sizeof(struct esp_flash_mapping)); + if (flash_map->maps_num > ESP_FLASH_MAPS_MAX) { + LOG_ERROR("Too many flash mappings %d! Must be %d.", flash_map->maps_num, ESP_FLASH_MAPS_MAX); + ret = ERROR_FAIL; + } else if (flash_map->maps_num == 0) { + LOG_WARNING("Empty flash mapping!"); + } else { + for (unsigned int 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_algo_flash_erase(struct flash_bank *bank, unsigned int first, unsigned 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(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; + } + + struct duration bench; + duration_start(&bench); + + int ret = esp_algo_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 */ + image_close(&run.image.image); + 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 (%" PRId32 ")!", run.ret_code); + ret = ERROR_FAIL; + } else { + duration_measure(&bench); + LOG_INFO("PROF: Erased %d bytes in %g ms", + (last - first + 1) * esp_info->sec_sz, + duration_elapsed(&bench) * 1000); + } + return ret; +} + +static int esp_algo_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; + } + busy_num = 0; + if (rw->total_count < rw->count && target->state != TARGET_DEBUG_RUNNING) { + LOG_ERROR("Algorithm accidentally stopped (%d)! Transferred %" PRIu32 " of %" + PRIu32, + target->state, + rw->total_count, + rw->count); + return ERROR_FAIL; + } + alive_sleep(10); + target_poll(target); + } + 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_algo_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_algo_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_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_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_algo_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_working_area(target, state->target_buf); + target_free_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_algo_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_algo_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_algo_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_algo_flash_apptrace_info_init(bank->target, + esp_info, + stub_cfg->apptrace_ctrl_addr, + &old_addr); + if (ret != ERROR_OK) + return ret; + + ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg); + if (ret != ERROR_OK) { + esp_algo_flash_apptrace_info_restore(bank->target, esp_info, old_addr); + return ret; + } + + run.stack_size = stack_size + stub_cfg->stack_data_pool_sz; + run.usr_func = esp_algo_flash_rw_do; + run.usr_func_arg = &wr_state; + run.usr_func_init = (algorithm_usr_func_init_t)esp_algo_flash_write_state_init; + run.usr_func_done = (algorithm_usr_func_done_t)esp_algo_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_algo_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; + wr_state.stub_wargs.options = ESP_STUB_FLASH_WR_RAW; + if (esp_info->encryption_needed_on_chip) + wr_state.stub_wargs.options |= ESP_STUB_FLASH_ENCRYPT_BINARY; + + struct duration wr_time; + duration_start(&wr_time); + + 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 */); + image_close(&run.image.image); + if (compressed_buff) + free(compressed_buff); + esp_algo_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 (%" PRId32 ")!", run.ret_code); + ret = ERROR_FAIL; + } else { + duration_measure(&wr_time); + LOG_INFO("PROF: Wrote %d bytes in %g ms (data transfer time included)", + wr_state.stub_wargs.total_size, + duration_elapsed(&wr_time) * 1000); + } + return ret; +} + +static int esp_algo_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(target, 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_algo_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_algo_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_algo_flash_apptrace_info_init(bank->target, + esp_info, + stub_cfg->apptrace_ctrl_addr, + &old_addr); + if (ret != ERROR_OK) + return ret; + + ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg); + if (ret != ERROR_OK) { + esp_algo_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_algo_flash_read_state_init; + run.usr_func = esp_algo_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_algo_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); + image_close(&run.image.image); + free(rd_state.rd_buf); + esp_algo_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 (%" PRId32 ")!", 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_algo_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_algo_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 = esp_algo_flash_get_size(bank); + drom_base = irom_base; + } else { + /* flash map index 0 belongs to drom */ + if (esp_info->is_drom_address(flash_map.maps[0].load_addr)) { + drom_flash_base = flash_map.maps[0].load_addr & ~(esp_info->sec_sz - 1); + drom_base = flash_map.maps[0].load_addr & ~(esp_info->sec_sz - 1); + drom_sz = flash_map.maps[0].size; + if (drom_sz & (esp_info->sec_sz - 1)) + drom_sz = (drom_sz & ~(esp_info->sec_sz - 1)) + esp_info->sec_sz; + } + /* flash map index 1 belongs to irom */ + if (flash_map.maps_num > 1 && esp_info->is_irom_address(flash_map.maps[1].load_addr)) { + irom_flash_base = flash_map.maps[1].phy_addr & ~(esp_info->sec_sz - 1); + irom_base = flash_map.maps[1].load_addr & ~(esp_info->sec_sz - 1); + irom_sz = flash_map.maps[1].size; + if (irom_sz & (esp_info->sec_sz - 1)) + irom_sz = (irom_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_algo_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 IROM/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) { + LOG_ERROR("Failed to alloc mem for sectors!"); + return ERROR_FAIL; + } + for (unsigned 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_algo_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_algo_flash_probe(bank); +} + +static int esp_algo_target_to_flash_bank(struct target *target, + struct flash_bank **bank, char *bank_name_suffix, bool probe) +{ + if (!target || !bank) + 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) { + LOG_ERROR("Failed to find bank '%s'!", bank_name); + return retval; + } + } else {/* noprobe */ + *bank = get_flash_bank_by_name_noprobe(bank_name); + if (!(*bank)) { + LOG_ERROR("Failed to find bank '%s'!", bank_name); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int esp_algo_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_algo_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_algo_flash_cmd_appimage_flashoff_do, struct target *target) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Flash offset not specified!"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* update app image base */ + uint32_t appimage_flash_base = strtoul(CMD_ARGV[0], NULL, 16); + + int ret = esp_algo_flash_appimage_base_update(target, "irom", appimage_flash_base); + if (ret != ERROR_OK) + return ret; + ret = esp_algo_flash_appimage_base_update(target, "drom", appimage_flash_base); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_algo_flash_cmd_appimage_flashoff) +{ + return CALL_COMMAND_HANDLER(esp_algo_flash_cmd_appimage_flashoff_do, get_current_target(CMD_CTX)); +} + +const struct command_registration esp_flash_exec_flash_command_handlers[] = { + { + .name = "appimage_offset", + .handler = esp_algo_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", + }, + 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..dcb694084e --- /dev/null +++ b/src/flash/nor/esp_flash.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Generic flash driver for Espressif chips * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_ESP_FLASH_H +#define OPENOCD_FLASH_NOR_ESP_FLASH_H + +#include <target/target.h> +#include <helper/command.h> +#include <target/espressif/esp_algorithm.h> +#include <target/breakpoints.h> +#include <flash/nor/core.h> + +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)(struct target *target, 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; + target_addr_t log_buff_addr; + uint32_t log_buff_size; /* current_log_len + len(buff) */ + target_addr_t iram_org; + uint32_t iram_len; + target_addr_t dram_org; + uint32_t dram_len; + /* ibus address range can be in reverse order compared to dbus */ + bool reverse; +}; + +/* 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; + /* Inform stub flasher if encryption requires before writing to flash. */ + int encryption_needed_on_chip; + /* Enable/disable stub log*/ + bool stub_log_enabled; +}; + +int esp_algo_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_algo_flash_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last); +int esp_algo_flash_protect_check(struct flash_bank *bank); +int esp_algo_flash_blank_check(struct flash_bank *bank); +int esp_algo_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last); +int esp_algo_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); +int esp_algo_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); +int esp_algo_flash_probe(struct flash_bank *bank); +int esp_algo_flash_auto_probe(struct flash_bank *bank); + +extern const struct command_registration esp_flash_exec_flash_command_handlers[]; + +COMMAND_HELPER(esp_algo_flash_cmd_appimage_flashoff_do, struct target *target); + +#endif /* OPENOCD_FLASH_NOR_ESP_FLASH_H */ diff --git a/src/flash/nor/esp_xtensa.c b/src/flash/nor/esp_xtensa.c new file mode 100644 index 0000000000..86459b7546 --- /dev/null +++ b/src/flash/nor/esp_xtensa.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP Xtensa flash driver for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "esp_xtensa.h" +#include <target/espressif/esp_xtensa_apptrace.h> +#include <target/xtensa/xtensa_algorithm.h> + +#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, +}; + +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_flasher_stub_config *(*get_stub)(struct flash_bank *bank)) +{ + memset(esp_info, 0, sizeof(*esp_info)); + int ret = esp_algo_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; +} diff --git a/src/flash/nor/esp_xtensa.h b/src/flash/nor/esp_xtensa.h new file mode 100644 index 0000000000..3c7e2f981c --- /dev/null +++ b/src/flash/nor/esp_xtensa.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Generic flash driver for Espressif Xtensa chips * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_ESP_XTENSA_H +#define OPENOCD_FLASH_NOR_ESP_XTENSA_H + +#include "esp_flash.h" + +/* 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 { + struct esp_flash_bank esp; +}; + +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_flasher_stub_config *(*get_stub)(struct flash_bank *bank)); + +#endif /* OPENOCD_FLASH_NOR_ESP_XTENSA_H */ diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c index 884224116e..fa32a23258 100644 --- a/src/target/espressif/esp32_apptrace.c +++ b/src/target/espressif/esp32_apptrace.c @@ -812,6 +812,12 @@ static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx, return ERROR_OK; } +uint8_t *esp_apptrace_usr_block_get(struct target *target, uint8_t *buffer, uint32_t *size) +{ + *size = target_buffer_get_u16(target, buffer + APPTRACE_WR_SIZE_OFFSET); + return buffer + sizeof(struct esp_apptrace_target2host_hdr); +} + int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, uint32_t block_id, const uint8_t *data, diff --git a/src/target/espressif/esp32_apptrace.h b/src/target/espressif/esp32_apptrace.h index 3873342226..d0321d66cc 100644 --- a/src/target/espressif/esp32_apptrace.h +++ b/src/target/espressif/esp32_apptrace.h @@ -120,6 +120,7 @@ int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct targ uint32_t block_id, const uint8_t *data, uint32_t size); +uint8_t *esp_apptrace_usr_block_get(struct target *target, uint8_t *buffer, uint32_t *size); extern const struct command_registration esp32_apptrace_command_handlers[]; --