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 = &mp;
+       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 = &mp;
+       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[];
 

-- 


Reply via email to