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/+/7760

-- gerrit

commit f992457db0ef6c46ea7d4f35192107914c187404
Author: Erhan Kurubas <erhan.kuru...@espressif.com>
Date:   Tue Jul 4 05:23:46 2023 +0200

    target/xtensa: add arch level algorithm support to execute code on target
    
    Also includes Xtensa flasher stub jumper binary.
    
    Signed-off-by: Erhan Kurubas <erhan.kuru...@espressif.com>
    Change-Id: Ie67993e4100cca7264ffa7a868ee2b2f1268c723

diff --git a/src/target/espressif/esp.c b/src/target/espressif/esp.c
index e7257a7bf4..6c43f544d3 100644
--- a/src/target/espressif/esp.c
+++ b/src/target/espressif/esp.c
@@ -14,6 +14,13 @@
 #include "target/target.h"
 #include "esp.h"
 
+int esp_common_init(struct esp_common *esp, const struct algorithm_hw *algo_hw)
+{
+       esp->algo_hw = algo_hw;
+
+       return ERROR_OK;
+}
+
 int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs 
*dbg_stubs)
 {
        uint32_t table_size, table_start_id, desc_entry_id, gcov_entry_id;
diff --git a/src/target/espressif/esp.h b/src/target/espressif/esp.h
index 3ba2b8bcfa..d629f031b5 100644
--- a/src/target/espressif/esp.h
+++ b/src/target/espressif/esp.h
@@ -77,9 +77,11 @@ struct esp_dbg_stubs {
 };
 
 struct esp_common {
+       const struct algorithm_hw *algo_hw;
        struct esp_dbg_stubs dbg_stubs;
 };
 
+int esp_common_init(struct esp_common *esp,    const struct algorithm_hw 
*algo_hw);
 int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs 
*dbg_stubs);
 
 #endif /* OPENOCD_TARGET_ESP_H */
diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c
index 5cc236c36f..d11857d176 100644
--- a/src/target/espressif/esp32.c
+++ b/src/target/espressif/esp32.c
@@ -496,6 +496,10 @@ struct target_type esp32_target = {
        .get_gdb_arch = xtensa_get_gdb_arch,
        .get_gdb_reg_list = xtensa_get_gdb_reg_list,
 
+       .run_algorithm = xtensa_run_algorithm,
+       .start_algorithm = xtensa_start_algorithm,
+       .wait_algorithm = xtensa_wait_algorithm,
+
        .add_breakpoint = esp_xtensa_breakpoint_add,
        .remove_breakpoint = esp_xtensa_breakpoint_remove,
 
diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c
index 3628cc0931..35ed8190fd 100644
--- a/src/target/espressif/esp32s2.c
+++ b/src/target/espressif/esp32s2.c
@@ -542,6 +542,10 @@ struct target_type esp32s2_target = {
        .get_gdb_arch = xtensa_get_gdb_arch,
        .get_gdb_reg_list = xtensa_get_gdb_reg_list,
 
+       .run_algorithm = xtensa_run_algorithm,
+       .start_algorithm = xtensa_start_algorithm,
+       .wait_algorithm = xtensa_wait_algorithm,
+
        .add_breakpoint = esp_xtensa_breakpoint_add,
        .remove_breakpoint = esp_xtensa_breakpoint_remove,
 
diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c
index 074155f6a6..f150a91a68 100644
--- a/src/target/espressif/esp32s3.c
+++ b/src/target/espressif/esp32s3.c
@@ -415,6 +415,10 @@ struct target_type esp32s3_target = {
        .get_gdb_arch = xtensa_get_gdb_arch,
        .get_gdb_reg_list = xtensa_get_gdb_reg_list,
 
+       .run_algorithm = xtensa_run_algorithm,
+       .start_algorithm = xtensa_start_algorithm,
+       .wait_algorithm = xtensa_wait_algorithm,
+
        .add_breakpoint = esp_xtensa_breakpoint_add,
        .remove_breakpoint = esp_xtensa_breakpoint_remove,
 
diff --git a/src/target/espressif/esp_xtensa.c 
b/src/target/espressif/esp_xtensa.c
index 72d6c202f6..44671b6303 100644
--- a/src/target/espressif/esp_xtensa.c
+++ b/src/target/espressif/esp_xtensa.c
@@ -12,6 +12,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <target/smp.h>
+#include <target/xtensa/xtensa_algorithm.h>
+#include "esp.h"
 #include "esp_xtensa_apptrace.h"
 #include <target/register.h>
 #include "esp_xtensa.h"
@@ -64,6 +66,9 @@ int esp_xtensa_init_arch_info(struct target *target,
        const struct esp_semihost_ops *semihost_ops)
 {
        int ret = xtensa_init_arch_info(target, &esp_xtensa->xtensa, dm_cfg);
+       if (ret != ERROR_OK)
+               return ret;
+       ret = esp_common_init(&esp_xtensa->esp, &xtensa_algo_hw);
        if (ret != ERROR_OK)
                return ret;
        esp_xtensa->semihost.ops = (struct esp_semihost_ops *)semihost_ops;
diff --git a/src/target/espressif/esp_xtensa_smp.h 
b/src/target/espressif/esp_xtensa_smp.h
index 6bfc713ffd..79bc35d2d8 100644
--- a/src/target/espressif/esp_xtensa_smp.h
+++ b/src/target/espressif/esp_xtensa_smp.h
@@ -8,8 +8,8 @@
 #ifndef OPENOCD_TARGET_XTENSA_ESP_SMP_H
 #define OPENOCD_TARGET_XTENSA_ESP_SMP_H
 
-#include "esp_xtensa.h"
 #include "esp_algorithm.h"
+#include "esp_xtensa.h"
 
 struct esp_xtensa_smp_chip_ops {
        int (*poll)(struct target *target);
diff --git a/src/target/xtensa/Makefile.am b/src/target/xtensa/Makefile.am
index 22504e78b2..486b434ce6 100644
--- a/src/target/xtensa/Makefile.am
+++ b/src/target/xtensa/Makefile.am
@@ -6,6 +6,8 @@ noinst_LTLIBRARIES += %D%/libxtensa.la
        %D%/xtensa.h \
        %D%/xtensa_chip.c \
        %D%/xtensa_chip.h \
+       %D%/xtensa_algorithm.c \
+       %D%/xtensa_algorithm.h \
        %D%/xtensa_debug_module.c \
        %D%/xtensa_debug_module.h \
        %D%/xtensa_fileio.c \
diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c
index 431c36a249..a7cd508d62 100644
--- a/src/target/xtensa/xtensa.c
+++ b/src/target/xtensa/xtensa.c
@@ -16,9 +16,11 @@
 #include <helper/time_support.h>
 #include <helper/align.h>
 #include <target/register.h>
+#include <target/algorithm.h>
 
 #include "xtensa_chip.h"
 #include "xtensa.h"
+#include "xtensa_algorithm.h"
 
 /* Swap 4-bit Xtensa opcodes and fields */
 #define XT_NIBSWAP8(V)                                                         
        \
@@ -2635,6 +2637,210 @@ int xtensa_watchpoint_remove(struct target *target, 
struct watchpoint *watchpoin
        return ERROR_OK;
 }
 
+int xtensa_start_algorithm(struct target *target,
+       int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t entry_point, target_addr_t exit_point,
+       void *arch_info)
+{
+       struct xtensa *xtensa = target_to_xtensa(target);
+       struct xtensa_algorithm *algorithm_info = arch_info;
+       int retval = ERROR_OK;
+       bool usr_ps = false;
+
+       /* NOTE: xtensa_run_algorithm requires that each algorithm uses a 
software breakpoint
+        * at the exit point */
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("Target not halted!");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       for (unsigned int i = 0; i < xtensa->core_cache->num_regs; i++) {
+               struct reg *reg = &xtensa->core_cache->reg_list[i];
+               buf_cpy(reg->value, xtensa->algo_context_backup[i], reg->size);
+       }
+       /* save debug reason, it will be changed */
+       algorithm_info->ctx_debug_reason = target->debug_reason;
+       /* write mem params */
+       for (int i = 0; i < num_mem_params; i++) {
+               if (mem_params[i].direction != PARAM_IN) {
+                       retval = target_write_buffer(target, 
mem_params[i].address,
+                               mem_params[i].size,
+                               mem_params[i].value);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+       }
+       /* write reg params */
+       for (int i = 0; i < num_reg_params; i++) {
+               assert(reg_params[i].size <= 32);
+               struct reg *reg = register_get_by_name(xtensa->core_cache, 
reg_params[i].reg_name, 0);
+               if (!reg) {
+                       LOG_ERROR("BUG: register '%s' not found", 
reg_params[i].reg_name);
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               if (reg->size != reg_params[i].size) {
+                       LOG_ERROR("BUG: register '%s' size doesn't match 
reg_params[i].size", reg_params[i].reg_name);
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               if (memcmp(reg_params[i].reg_name, "ps", 3)) {
+                       usr_ps = true;
+               } else {
+                       unsigned int reg_id = xtensa->eps_dbglevel_idx;
+                       assert(reg_id < xtensa->core_cache->num_regs && 
"Attempt to access non-existing reg!");
+                       reg = &xtensa->core_cache->reg_list[reg_id];
+               }
+               xtensa_reg_set_value(reg, buf_get_u32(reg_params[i].value, 0, 
reg->size));
+               reg->valid = 1;
+       }
+       /* ignore custom core mode if custom PS value is specified */
+       if (!usr_ps) {
+               unsigned int eps_reg_idx = xtensa->eps_dbglevel_idx;
+               xtensa_reg_val_t ps = xtensa_reg_get(target, eps_reg_idx);
+               enum xtensa_mode core_mode = XT_PS_RING_GET(ps);
+               if (algorithm_info->core_mode != XT_MODE_ANY && 
algorithm_info->core_mode != core_mode) {
+                       LOG_DEBUG("setting core_mode: 0x%x", 
algorithm_info->core_mode);
+                       xtensa_reg_val_t new_ps = (ps & ~XT_PS_RING_MSK) | 
XT_PS_RING(algorithm_info->core_mode);
+                       /* save previous core mode */
+                       algorithm_info->core_mode = core_mode;
+                       xtensa_reg_set(target, eps_reg_idx, new_ps);
+                       xtensa->core_cache->reg_list[eps_reg_idx].valid = 1;
+               }
+       }
+
+       return xtensa_resume(target, 0, entry_point, 1, 1);
+}
+
+/** Waits for an algorithm in the target. */
+int xtensa_wait_algorithm(struct target *target,
+       int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t exit_point, unsigned int timeout_ms,
+       void *arch_info)
+{
+       struct xtensa *xtensa = target_to_xtensa(target);
+       struct xtensa_algorithm *algorithm_info = arch_info;
+       int retval = ERROR_OK;
+       xtensa_reg_val_t pc;
+
+       /* NOTE: xtensa_run_algorithm requires that each algorithm uses a 
software breakpoint
+        * at the exit point */
+
+       retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
+       /* If the target fails to halt due to the breakpoint, force a halt */
+       if (retval != ERROR_OK || target->state != TARGET_HALTED) {
+               retval = target_halt(target);
+               if (retval != ERROR_OK)
+                       return retval;
+               retval = target_wait_state(target, TARGET_HALTED, 500);
+               if (retval != ERROR_OK)
+                       return retval;
+               LOG_TARGET_ERROR(target, "not halted %d, pc 0x%x, ps 0x%x", 
retval,
+                       xtensa_reg_get(target, XT_REG_IDX_PC),
+                       xtensa_reg_get(target, xtensa->eps_dbglevel_idx));
+               return ERROR_TARGET_TIMEOUT;
+       }
+       pc = xtensa_reg_get(target, XT_REG_IDX_PC);
+       if (exit_point && pc != exit_point) {
+               LOG_ERROR("failed algorithm halted at 0x%" PRIx32 ", expected " 
TARGET_ADDR_FMT, pc, exit_point);
+               return ERROR_TARGET_TIMEOUT;
+       }
+       /* Copy core register values to reg_params[] */
+       for (int i = 0; i < num_reg_params; i++) {
+               if (reg_params[i].direction != PARAM_OUT) {
+                       struct reg *reg = 
register_get_by_name(xtensa->core_cache, reg_params[i].reg_name, 0);
+                       if (!reg) {
+                               LOG_ERROR("BUG: register '%s' not found", 
reg_params[i].reg_name);
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       }
+                       if (reg->size != reg_params[i].size) {
+                               LOG_ERROR("BUG: register '%s' size doesn't 
match reg_params[i].size", reg_params[i].reg_name);
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       }
+                       buf_set_u32(reg_params[i].value, 0, 32, 
xtensa_reg_get_value(reg));
+               }
+       }
+       /* Read memory values to mem_params */
+       LOG_DEBUG("Read mem params");
+       for (int i = 0; i < num_mem_params; i++) {
+               LOG_DEBUG("Check mem param @ " TARGET_ADDR_FMT, 
mem_params[i].address);
+               if (mem_params[i].direction != PARAM_OUT) {
+                       LOG_DEBUG("Read mem param @ " TARGET_ADDR_FMT, 
mem_params[i].address);
+                       retval = target_read_buffer(target, 
mem_params[i].address, mem_params[i].size, mem_params[i].value);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+       }
+
+       /* avoid gdb keep_alive warning */
+       keep_alive();
+
+       for (int i = xtensa->core_cache->num_regs - 1; i >= 0; i--) {
+               struct reg *reg = &xtensa->core_cache->reg_list[i];
+               if (i == XT_REG_IDX_PS) {
+                       continue;       /* restore mapped reg number of PS 
depends on NDEBUGLEVEL */
+               } else if (i == XT_REG_IDX_DEBUGCAUSE) {
+                       /*FIXME: restoring DEBUGCAUSE causes exception when 
executing corresponding
+                       * instruction in DIR */
+                       LOG_DEBUG("Skip restoring register %s: 0x%8.8" PRIx32 " 
-> 0x%8.8" PRIx32,
+                               xtensa->core_cache->reg_list[i].name,
+                               buf_get_u32(reg->value, 0, 32),
+                               buf_get_u32(xtensa->algo_context_backup[i], 0, 
32));
+                       buf_cpy(xtensa->algo_context_backup[i], reg->value, 
reg->size);
+                       xtensa->core_cache->reg_list[i].dirty = 0;
+                       xtensa->core_cache->reg_list[i].valid = 0;
+               } else if (memcmp(xtensa->algo_context_backup[i], reg->value, 
reg->size / 8)) {
+                       if (reg->size <= 32) {
+                               LOG_DEBUG("restoring register %s: 0x%8.8" 
PRIx32 " -> 0x%8.8" PRIx32,
+                                       xtensa->core_cache->reg_list[i].name,
+                                       buf_get_u32(reg->value, 0, reg->size),
+                                       
buf_get_u32(xtensa->algo_context_backup[i], 0, reg->size));
+                       } else if (reg->size <= 64) {
+                               LOG_DEBUG("restoring register %s: 0x%8.8" 
PRIx64 " -> 0x%8.8" PRIx64,
+                                       xtensa->core_cache->reg_list[i].name,
+                                       buf_get_u64(reg->value, 0, reg->size),
+                                       
buf_get_u64(xtensa->algo_context_backup[i], 0, reg->size));
+                       } else {
+                               LOG_DEBUG("restoring register %s %u-bits", 
xtensa->core_cache->reg_list[i].name, reg->size);
+                       }
+                       buf_cpy(xtensa->algo_context_backup[i], reg->value, 
reg->size);
+                       xtensa->core_cache->reg_list[i].dirty = 1;
+                       xtensa->core_cache->reg_list[i].valid = 1;
+               }
+       }
+       target->debug_reason = algorithm_info->ctx_debug_reason;
+
+       retval = xtensa_write_dirty_registers(target);
+       if (retval != ERROR_OK)
+               LOG_ERROR("Failed to write dirty regs (%d)!", retval);
+
+       return retval;
+}
+
+int xtensa_run_algorithm(struct target *target,
+       int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t entry_point, target_addr_t exit_point,
+       unsigned int timeout_ms, void *arch_info)
+{
+       int retval = xtensa_start_algorithm(target,
+               num_mem_params, mem_params,
+               num_reg_params, reg_params,
+               entry_point, exit_point,
+               arch_info);
+
+       if (retval == ERROR_OK) {
+               retval = xtensa_wait_algorithm(target,
+                       num_mem_params, mem_params,
+                       num_reg_params, reg_params,
+                       exit_point, timeout_ms,
+                       arch_info);
+       }
+
+       return retval;
+}
+
 static int xtensa_build_reg_cache(struct target *target)
 {
        struct xtensa *xtensa = target_to_xtensa(target);
diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h
index 4216ae24f6..24a649b74b 100644
--- a/src/target/xtensa/xtensa.h
+++ b/src/target/xtensa/xtensa.h
@@ -395,6 +395,21 @@ int xtensa_breakpoint_add(struct target *target, struct 
breakpoint *breakpoint);
 int xtensa_breakpoint_remove(struct target *target, struct breakpoint 
*breakpoint);
 int xtensa_watchpoint_add(struct target *target, struct watchpoint 
*watchpoint);
 int xtensa_watchpoint_remove(struct target *target, struct watchpoint 
*watchpoint);
+int xtensa_start_algorithm(struct target *target,
+       int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t entry_point, target_addr_t exit_point,
+       void *arch_info);
+int xtensa_wait_algorithm(struct target *target,
+       int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t exit_point, unsigned int timeout_ms,
+       void *arch_info);
+int xtensa_run_algorithm(struct target *target,
+       int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t entry_point, target_addr_t exit_point,
+       unsigned int timeout_ms, void *arch_info);
 void xtensa_set_permissive_mode(struct target *target, bool state);
 const char *xtensa_get_gdb_arch(struct target *target);
 int xtensa_gdb_query_custom(struct target *target, const char *packet, char 
**response_p);
diff --git a/src/target/xtensa/xtensa_algorithm.c 
b/src/target/xtensa/xtensa_algorithm.c
new file mode 100644
index 0000000000..7c5ac0bcc7
--- /dev/null
+++ b/src/target/xtensa/xtensa_algorithm.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Module to run arbitrary code on Xtensa using OpenOCD                  *
+ *   Copyright (C) 2019 Espressif Systems Ltd.                             *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xtensa.h"
+#include "xtensa_algorithm.h"
+
+static int xtensa_algo_init(struct target *target, struct algorithm_run_data 
*run,
+       uint32_t num_args, va_list ap);
+static int xtensa_algo_cleanup(struct target *target, struct 
algorithm_run_data *run);
+static const uint8_t *xtensa_stub_tramp_get(struct target *target, size_t 
*size);
+
+const struct algorithm_hw xtensa_algo_hw = {
+       .algo_init = xtensa_algo_init,
+       .algo_cleanup = xtensa_algo_cleanup,
+       .stub_tramp_get = xtensa_stub_tramp_get,
+};
+
+static const uint8_t xtensa_stub_tramp_win[] = {
+#include "src/target/xtensa/xtensa_stub_tramp_win.inc"
+};
+
+static const uint8_t *xtensa_stub_tramp_get(struct target *target, size_t 
*size)
+{
+       struct xtensa *xtensa = target_to_xtensa(target);
+
+       if (!xtensa->core_config->windowed) {
+               LOG_ERROR("Running stubs is not supported for cores without 
windowed registers option!");
+               return NULL;
+       }
+       *size = sizeof(xtensa_stub_tramp_win);
+       return xtensa_stub_tramp_win;
+}
+
+static int xtensa_algo_regs_init_start(struct target *target, struct 
algorithm_run_data *run)
+{
+       uint32_t stack_addr = run->stub.stack_addr;
+
+       LOG_DEBUG("Check stack addr 0x%x", stack_addr);
+       if (stack_addr & 0xFUL) {
+               stack_addr &= ~0xFUL;
+               LOG_DEBUG("Adjust stack addr to 0x%x", stack_addr);
+       }
+       stack_addr -= 16;
+       struct reg_param *params = run->reg_args.params;
+       init_reg_param(&params[0], "a0", 32, PARAM_OUT);                /*TODO: 
move to tramp */
+       init_reg_param(&params[1], "a1", 32, PARAM_OUT);
+       init_reg_param(&params[2], "a8", 32, PARAM_OUT);
+       init_reg_param(&params[3], "windowbase", 32, PARAM_OUT);        /*TODO: 
move to tramp */
+       init_reg_param(&params[4], "windowstart", 32, PARAM_OUT);       /*TODO: 
move to tramp */
+       init_reg_param(&params[5], "ps", 32, PARAM_OUT);
+       buf_set_u32(params[0].value, 0, 32, 0); /* a0 TODO: move to tramp */
+       buf_set_u32(params[1].value, 0, 32, stack_addr);        /* a1 */
+       buf_set_u32(params[2].value, 0, 32, run->stub.entry);   /* a8 */
+       buf_set_u32(params[3].value, 0, 32, 0x0);       /* initial window base 
TODO: move to tramp */
+       buf_set_u32(params[4].value, 0, 32, 0x1);       /* initial window start 
TODO: move to tramp */
+       buf_set_u32(params[5].value, 0, 32, 0x60025);   /* enable WOE, UM and 
debug interrupts level (6) */
+       return ERROR_OK;
+}
+
+static int xtensa_algo_init(struct target *target, struct algorithm_run_data 
*run,
+       uint32_t num_args, va_list ap)
+{
+       enum xtensa_mode core_mode = XT_MODE_ANY;
+       static const char *const arg_regs[] = { "a2", "a3", "a4", "a5", "a6" };
+
+       if (num_args > ARRAY_SIZE(arg_regs)) {
+               LOG_ERROR("Too many algo user args %u! Max %zu args are 
supported.", num_args, ARRAY_SIZE(arg_regs));
+               return ERROR_FAIL;
+       }
+
+       if (run->arch_info) {
+               struct xtensa_algorithm *xtensa_algo = run->arch_info;
+               core_mode = xtensa_algo->core_mode;
+       }
+
+       run->reg_args.first_user_param = XTENSA_STUB_ARGS_FUNC_START;
+       run->reg_args.count = run->reg_args.first_user_param + num_args;
+       if (num_args == 0)
+               run->reg_args.count++;  /*a2 reg is used as the 1st arg and 
return code*/
+       LOG_DEBUG("reg params count %d (%d/%d).",
+               run->reg_args.count,
+               run->reg_args.first_user_param,
+               num_args);
+       run->reg_args.params = calloc(run->reg_args.count, sizeof(struct 
reg_param));
+       assert(run->reg_args.params);
+
+       xtensa_algo_regs_init_start(target, run);
+
+       init_reg_param(&run->reg_args.params[run->reg_args.first_user_param + 
0], "a2", 32, PARAM_IN_OUT);
+
+       if (num_args > 0) {
+               uint32_t arg = va_arg(ap, uint32_t);
+               algorithm_user_arg_set_uint(run, 0, arg);
+               LOG_DEBUG("Set arg[0] = %d (%s)", arg, 
run->reg_args.params[run->reg_args.first_user_param + 0].reg_name);
+       } else {
+               algorithm_user_arg_set_uint(run, 0, 0);
+       }
+
+       for (unsigned int i = 1; i < num_args; i++) {
+               uint32_t arg = va_arg(ap, uint32_t);
+               
init_reg_param(&run->reg_args.params[run->reg_args.first_user_param + i], (char 
*)arg_regs[i], 32, PARAM_OUT);
+               algorithm_user_arg_set_uint(run, i, arg);
+               LOG_DEBUG("Set arg[%d] = %d (%s)", i, arg,
+                       run->reg_args.params[run->reg_args.first_user_param + 
i].reg_name);
+       }
+       struct xtensa_algorithm *ainfo = calloc(1, sizeof(struct 
xtensa_algorithm));
+       assert(ainfo);
+       ainfo->core_mode = core_mode;
+       run->stub.ainfo = ainfo;
+       return ERROR_OK;
+}
+
+static int xtensa_algo_cleanup(struct target *target, struct 
algorithm_run_data *run)
+{
+       free(run->stub.ainfo);
+       for (uint32_t i = 0; i < run->reg_args.count; i++)
+               destroy_reg_param(&run->reg_args.params[i]);
+       free(run->reg_args.params);
+       return ERROR_OK;
+}
diff --git a/src/target/xtensa/xtensa_algorithm.h 
b/src/target/xtensa/xtensa_algorithm.h
new file mode 100644
index 0000000000..d4b44b5a75
--- /dev/null
+++ b/src/target/xtensa/xtensa_algorithm.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Module to run arbitrary code on Xtensa using OpenOCD                  *
+ *   Copyright (C) 2019 Espressif Systems Ltd.                             *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_XTENSA_ALGO_H
+#define OPENOCD_TARGET_XTENSA_ALGO_H
+
+#include "xtensa.h"
+#include <target/espressif/esp_algorithm.h>
+
+/** Index of the first user-defined algo arg. @see algorithm_stub */
+#define XTENSA_STUB_ARGS_FUNC_START             6
+
+/**
+ * Xtensa algorithm data.
+ */
+struct xtensa_algorithm {
+       /** User can set this to specify which core mode algorithm should be 
run in. */
+       enum xtensa_mode core_mode;
+       /** Used internally to backup and restore debug_reason. */
+       enum target_debug_reason ctx_debug_reason;
+};
+
+extern const struct algorithm_hw xtensa_algo_hw;
+
+#endif /* OPENOCD_TARGET_XTENSA_ALGO_H */
diff --git a/src/target/xtensa/xtensa_stub_tramp_win.S 
b/src/target/xtensa/xtensa_stub_tramp_win.S
new file mode 100644
index 0000000000..18d0ed49f0
--- /dev/null
+++ b/src/target/xtensa/xtensa_stub_tramp_win.S
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Xtensa flasher stub wrapper                                           *
+ *   Copyright (C) 2017 Espressif Systems Ltd.                             *
+ ***************************************************************************/
+
+/* To assemble:
+ * xtensa-esp32-elf-gcc -c xtensa_stub_tramp_win.S -o xtensa_stub_tramp_win.o
+ *
+ * To disassemble:
+ * xtensa-esp32-elf-objdump -d xtensa_stub_tramp_win.o
+ *
+ * To generate binary file:
+ * xtensa-esp32-elf-objcopy -O binary xtensa_stub_tramp_win.o 
xtensa_stub_tramp_win.bin
+ *
+ * To generate include file:
+ * ../../../src/helper/bin2char.sh < xtensa_stub_tramp_win.bin > 
xtensa_stub_tramp_win.inc
+ */
+
+/*
+ * Expects :
+ * a0 = zero
+ * a1 = stack_base + stack_size - 16, 16 bytes aligned
+ * a8 = address of the function to call
+ * Params :
+ * a2 = command arg0, result (out)
+ * a3 = command arg1
+ * a4 = command arg2
+ * a5 = command arg3
+ * a6 = command arg4
+ * Maximum 5 user args
+ */
+    .text
+
+    .align  4
+_stub_enter:
+    /* initialize initial stack frame for callx8 */
+    addi    a9, sp,  32 /* point 16 past extra save area */
+    s32e    a9, sp, -12 /* access to extra save area */
+    /* prepare args */
+    mov     a10, a2
+    mov     a11, a3
+    mov     a12, a4
+    mov     a13, a5
+    mov     a14, a6
+    /* call stub */
+    callx8  a8
+    /* prepare return value */
+    mov     a2, a10
+    break 0,0
+
+_idle_loop:
+    j _idle_loop
diff --git a/src/target/xtensa/xtensa_stub_tramp_win.inc 
b/src/target/xtensa/xtensa_stub_tramp_win.inc
new file mode 100644
index 0000000000..a82d0c76ab
--- /dev/null
+++ b/src/target/xtensa/xtensa_stub_tramp_win.inc
@@ -0,0 +1,4 @@
+/* Autogenerated with ../../../src/helper/bin2char.sh */
+0x92,0xc1,0x20,0x90,0xd1,0x49,0xad,0x02,0xbd,0x03,0xcd,0x04,0xdd,0x05,0x60,0xe6,
+0x20,0xe0,0x08,0x00,0x2d,0x0a,0x00,0x40,0x00,0x06,0xff,0xff,
+

-- 

Reply via email to