From bea4d6590356f4a9ef0bcb6b270943e565852f0e Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Thu, 30 Jun 2022 13:14:27 +0300 Subject: [PATCH] target/espressif: add semihosting support ARM semihosting + some custom syscalls implemented for Espressif chips (ESP32, ESP32-S2, ESP32-S3) Signed-off-by: Erhan Kurubas Change-Id: Ic8174cf1cd344fa16d619b7b8405c9650e869443 Reviewed-on: https://review.openocd.org/c/openocd/+/7074 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/espressif/Makefile.am | 6 +- src/target/espressif/esp32.c | 14 +- src/target/espressif/esp32s2.c | 34 ++++- src/target/espressif/esp32s3.c | 17 ++- src/target/espressif/esp_semihosting.c | 127 ++++++++++++++++++ src/target/espressif/esp_semihosting.h | 55 ++++++++ src/target/espressif/esp_xtensa.c | 12 +- src/target/espressif/esp_xtensa.h | 7 +- src/target/espressif/esp_xtensa_semihosting.c | 114 ++++++++++++++++ src/target/espressif/esp_xtensa_semihosting.h | 15 +++ src/target/espressif/esp_xtensa_smp.c | 45 ++++++- src/target/espressif/esp_xtensa_smp.h | 3 +- tcl/target/esp32.cfg | 27 ++++ tcl/target/esp32s2.cfg | 13 ++ tcl/target/esp32s3.cfg | 26 ++++ tcl/target/esp_common.cfg | 10 ++ 16 files changed, 510 insertions(+), 15 deletions(-) create mode 100644 src/target/espressif/esp_semihosting.c create mode 100644 src/target/espressif/esp_semihosting.h create mode 100644 src/target/espressif/esp_xtensa_semihosting.c create mode 100644 src/target/espressif/esp_xtensa_semihosting.h create mode 100644 tcl/target/esp_common.cfg diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am index 1b4f8062e..8367a3881 100644 --- a/src/target/espressif/Makefile.am +++ b/src/target/espressif/Makefile.am @@ -6,6 +6,10 @@ noinst_LTLIBRARIES += %D%/libespressif.la %D%/esp_xtensa.h \ %D%/esp_xtensa_smp.c \ %D%/esp_xtensa_smp.h \ + %D%/esp_xtensa_semihosting.c \ + %D%/esp_xtensa_semihosting.h \ %D%/esp32.c \ %D%/esp32s2.c \ - %D%/esp32s3.c + %D%/esp32s3.c \ + %D%/esp_semihosting.c \ + %D%/esp_semihosting.h diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index a083627fb..8ad8bad83 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "assert.h" #include "esp_xtensa_smp.h" @@ -329,6 +330,10 @@ static const struct esp_xtensa_smp_chip_ops esp32_chip_ops = { .on_halt = esp32_on_halt }; +static const struct esp_semihost_ops esp32_semihost_ops = { + .prepare = esp32_disable_wdts +}; + static int esp32_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config esp32_dm_cfg = { @@ -346,7 +351,7 @@ static int esp32_target_create(struct target *target, Jim_Interp *interp) } int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp, - &esp32_dm_cfg, &esp32_chip_ops); + &esp32_dm_cfg, &esp32_chip_ops, &esp32_semihost_ops); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(esp32); @@ -445,6 +450,13 @@ static const struct command_registration esp32_command_handlers[] = { .usage = "", .chain = esp32_any_command_handlers, }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index 0bcd20f2d..4aef3791b 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -13,7 +13,9 @@ #include "assert.h" #include #include +#include #include "esp_xtensa.h" +#include "esp_xtensa_semihosting.h" /* Overall memory map * TODO: read memory configuration from target registers */ @@ -406,6 +408,19 @@ static int esp32s2_poll(struct target *target) if (old_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { + if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) { + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + if (ret == ERROR_OK && esp_xtensa->semihost.need_resume) { + esp_xtensa->semihost.need_resume = false; + /* Resume xtensa_resume will handle BREAK instruction. */ + ret = target_resume(target, 1, 0, 1, 0); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return ret; + } + } + return ret; + } esp32s2_on_halt(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } @@ -423,7 +438,11 @@ static int esp32s2_virt2phys(struct target *target, static int esp32s2_target_init(struct command_context *cmd_ctx, struct target *target) { - return esp_xtensa_target_init(cmd_ctx, target); + int ret = esp_xtensa_target_init(cmd_ctx, target); + if (ret != ERROR_OK) + return ret; + + return esp_xtensa_semihosting_init(target); } static const struct xtensa_debug_ops esp32s2_dbg_ops = { @@ -437,6 +456,10 @@ static const struct xtensa_power_ops esp32s2_pwr_ops = { .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; +static const struct esp_semihost_ops esp32s2_semihost_ops = { + .prepare = esp32s2_disable_wdts +}; + static int esp32s2_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config esp32s2_dm_cfg = { @@ -454,7 +477,7 @@ static int esp32s2_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; } - int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_dm_cfg); + int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_dm_cfg, &esp32s2_semihost_ops); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(esp32); @@ -471,6 +494,13 @@ static const struct command_registration esp32s2_command_handlers[] = { { .chain = xtensa_command_handlers, }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index b87005901..0da8552a3 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "assert.h" #include "esp_xtensa_smp.h" @@ -302,7 +303,7 @@ static int esp32s3_virt2phys(struct target *target, static int esp32s3_target_init(struct command_context *cmd_ctx, struct target *target) { - return esp_xtensa_target_init(cmd_ctx, target); + return esp_xtensa_smp_target_init(cmd_ctx, target); } static const struct xtensa_debug_ops esp32s3_dbg_ops = { @@ -321,6 +322,10 @@ static const struct esp_xtensa_smp_chip_ops esp32s3_chip_ops = { .on_halt = esp32s3_on_halt }; +static const struct esp_semihost_ops esp32s3_semihost_ops = { + .prepare = esp32s3_disable_wdts +}; + static int esp32s3_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config esp32s3_dm_cfg = { @@ -340,7 +345,8 @@ static int esp32s3_target_create(struct target *target, Jim_Interp *interp) int ret = esp_xtensa_smp_init_arch_info(target, &esp32s3->esp_xtensa_smp, &esp32s3_dm_cfg, - &esp32s3_chip_ops); + &esp32s3_chip_ops, + &esp32s3_semihost_ops); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(esp32s3); @@ -363,6 +369,13 @@ static const struct command_registration esp32s3_command_handlers[] = { .usage = "", .chain = smp_command_handlers, }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/espressif/esp_semihosting.c b/src/target/espressif/esp_semihosting.c new file mode 100644 index 000000000..b1edef31d --- /dev/null +++ b/src/target/espressif/esp_semihosting.c @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Semihosting API for Espressif chips * + * Copyright (C) 2022 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "esp_semihosting.h" +#include "esp_xtensa.h" + +struct esp_semihost_data *target_to_esp_semihost_data(struct target *target) +{ + const char *arch = target_get_gdb_arch(target); + if (arch) { + if (strncmp(arch, "xtensa", 6) == 0) + return &target_to_esp_xtensa(target)->semihost; + /* TODO: add riscv */ + } + LOG_ERROR("Unknown target arch!"); + return NULL; +} + +int esp_semihosting_sys_seek(struct target *target, uint64_t fd, uint32_t pos, size_t whence) +{ + struct semihosting *semihosting = target->semihosting; + + semihosting->result = lseek(fd, pos, whence); + semihosting->sys_errno = errno; + LOG_TARGET_DEBUG(target, "lseek(%" PRIx64 ", %" PRIu32 " %" PRId64 ")=%d", fd, pos, semihosting->result, errno); + return ERROR_OK; +} + +int esp_semihosting_common(struct target *target) +{ + struct semihosting *semihosting = target->semihosting; + if (!semihosting) + /* Silently ignore if the semihosting field was not set. */ + return ERROR_OK; + + int retval = ERROR_NOT_IMPLEMENTED; + + /* Enough space to hold 4 long words. */ + uint8_t fields[4 * 8]; + + /* + * By default return an error. + * The actual result must be set by each function + */ + semihosting->result = -1; + semihosting->sys_errno = EIO; + + LOG_TARGET_DEBUG(target, "op=0x%x, param=0x%" PRIx64, semihosting->op, semihosting->param); + + switch (semihosting->op) { + case ESP_SEMIHOSTING_SYS_DRV_INFO: + /* Return success to make esp-idf application happy */ + retval = ERROR_OK; + semihosting->result = 0; + semihosting->sys_errno = 0; + break; + + case ESP_SEMIHOSTING_SYS_SEEK: + retval = semihosting_read_fields(target, 3, fields); + if (retval == ERROR_OK) { + uint64_t fd = semihosting_get_field(target, 0, fields); + uint32_t pos = semihosting_get_field(target, 1, fields); + size_t whence = semihosting_get_field(target, 2, fields); + retval = esp_semihosting_sys_seek(target, fd, pos, whence); + } + break; + + case ESP_SEMIHOSTING_SYS_APPTRACE_INIT: + case ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT: + case ESP_SEMIHOSTING_SYS_BREAKPOINT_SET: + case ESP_SEMIHOSTING_SYS_WATCHPOINT_SET: + /* For the time being only riscv chips support these commands + * TODO: invoke riscv custom command handler */ + break; + } + + return retval; +} + +int esp_semihosting_basedir_command(struct command_invocation *cmd) +{ + struct target *target = get_current_target(CMD_CTX); + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + command_print(CMD, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + if (!semihosting->is_active) { + if (semihosting->setup(target, true) != ERROR_OK) { + LOG_ERROR("Failed to Configure semihosting"); + return ERROR_FAIL; + } + semihosting->is_active = true; + } + + if (CMD_ARGC > 0) { + free(semihosting->basedir); + semihosting->basedir = strdup(CMD_ARGV[0]); + if (!semihosting->basedir) { + command_print(CMD, "semihosting failed to allocate memory for basedir!"); + return ERROR_FAIL; + } + } + + command_print(CMD, "DEPRECATED! semihosting base dir: %s", + semihosting->basedir ? semihosting->basedir : ""); + + return ERROR_OK; +} diff --git a/src/target/espressif/esp_semihosting.h b/src/target/espressif/esp_semihosting.h new file mode 100644 index 000000000..bd2c0799e --- /dev/null +++ b/src/target/espressif/esp_semihosting.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Semihosting API for Espressif chips * + * Copyright (C) 2022 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_SEMIHOSTING_H +#define OPENOCD_TARGET_ESP_SEMIHOSTING_H + +/* Legacy syscalls */ +#define ESP_SYS_DRV_INFO_LEGACY 0xE0 + +/* syscalls compatible to ARM standard */ +#define ESP_SEMIHOSTING_SYS_DRV_INFO 0x100 +#define ESP_SEMIHOSTING_SYS_APPTRACE_INIT 0x101 +#define ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT 0x102 +#define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET 0x103 +#define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET 0x104 +#define ESP_SEMIHOSTING_SYS_SEEK 0x105 /* custom lseek with whence */ +/* not implemented yet */ +#define ESP_SEMIHOSTING_SYS_MKDIR 0x106 +#define ESP_SEMIHOSTING_SYS_OPENDIR 0x107 +#define ESP_SEMIHOSTING_SYS_READDIR 0x108 +#define ESP_SEMIHOSTING_SYS_READDIR_R 0x109 +#define ESP_SEMIHOSTING_SYS_SEEKDIR 0x10A +#define ESP_SEMIHOSTING_SYS_TELLDIR 0x10B +#define ESP_SEMIHOSTING_SYS_CLOSEDIR 0x10C +#define ESP_SEMIHOSTING_SYS_RMDIR 0x10D +#define ESP_SEMIHOSTING_SYS_ACCESS 0x10E +#define ESP_SEMIHOSTING_SYS_TRUNCATE 0x10F +#define ESP_SEMIHOSTING_SYS_UTIME 0x110 +#define ESP_SEMIHOSTING_SYS_FSTAT 0x111 +#define ESP_SEMIHOSTING_SYS_STAT 0x112 +#define ESP_SEMIHOSTING_SYS_FSYNC 0x113 +#define ESP_SEMIHOSTING_SYS_LINK 0x114 +#define ESP_SEMIHOSTING_SYS_UNLINK 0x115 + +/** + * Semihost calls handling operations. + */ +struct esp_semihost_ops { + /** Callback called before handling semihost call */ + int (*prepare)(struct target *target); +}; + +struct esp_semihost_data { + bool need_resume; + struct esp_semihost_ops *ops; +}; + +int esp_semihosting_common(struct target *target); +int esp_semihosting_basedir_command(struct command_invocation *cmd); + +#endif /* OPENOCD_TARGET_ESP_SEMIHOSTING_H */ diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index fcd42eac3..6a1b72ec4 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -12,14 +12,20 @@ #include #include #include -#include "esp_xtensa.h" #include +#include "esp_xtensa.h" +#include "esp_semihosting.h" int esp_xtensa_init_arch_info(struct target *target, struct esp_xtensa_common *esp_xtensa, - struct xtensa_debug_module_config *dm_cfg) + struct xtensa_debug_module_config *dm_cfg, + const struct esp_semihost_ops *semihost_ops) { - return xtensa_init_arch_info(target, &esp_xtensa->xtensa, dm_cfg); + int ret = xtensa_init_arch_info(target, &esp_xtensa->xtensa, dm_cfg); + if (ret != ERROR_OK) + return ret; + esp_xtensa->semihost.ops = (struct esp_semihost_ops *)semihost_ops; + return ERROR_OK; } int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target) diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h index 61e87c086..1ad6c377f 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -8,12 +8,14 @@ #ifndef OPENOCD_TARGET_ESP_XTENSA_H #define OPENOCD_TARGET_ESP_XTENSA_H -#include #include #include +#include "esp_xtensa.h" +#include "esp_semihosting.h" struct esp_xtensa_common { struct xtensa xtensa; /* must be the first element */ + struct esp_semihost_data semihost; }; static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target) @@ -23,7 +25,8 @@ static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *targ int esp_xtensa_init_arch_info(struct target *target, struct esp_xtensa_common *esp_xtensa, - struct xtensa_debug_module_config *dm_cfg); + struct xtensa_debug_module_config *dm_cfg, + const struct esp_semihost_ops *semihost_ops); int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target); void esp_xtensa_target_deinit(struct target *target); int esp_xtensa_arch_state(struct target *target); diff --git a/src/target/espressif/esp_xtensa_semihosting.c b/src/target/espressif/esp_xtensa_semihosting.c new file mode 100644 index 000000000..9ea8e4df5 --- /dev/null +++ b/src/target/espressif/esp_xtensa_semihosting.c @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "esp_xtensa.h" +#include "esp_xtensa_semihosting.h" + +#define ESP_XTENSA_SYSCALL 0x41E0 /* XT_INS_BREAK(1, 14) */ +#define ESP_XTENSA_SYSCALL_SZ 3 + +#define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2 +#define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2 +#define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3 + +static int esp_xtensa_semihosting_setup(struct target *target, int enable) +{ + LOG_TARGET_DEBUG(target, "semihosting enable=%d", enable); + + return ERROR_OK; +} + +static int esp_xtensa_semihosting_post_result(struct target *target) +{ + /* Even with the v2 and later, errno will not retrieved from A3 reg, it is safe to set */ + xtensa_reg_set(target, XTENSA_SYSCALL_RETVAL_REG, target->semihosting->result); + xtensa_reg_set(target, XTENSA_SYSCALL_ERRNO_REG, target->semihosting->sys_errno); + return ERROR_OK; +} + +/** + * Checks and processes an ESP Xtensa semihosting request. This is meant + * to be called when the target is stopped due to a debug mode entry. + * If the value 0 is returned then there was nothing to process. A non-zero + * return value signifies that a request was processed and the target resumed, + * or an error was encountered, in which case the caller must return immediately. + * + * @param target Pointer to the ESP Xtensa target to process. + * @param retval Pointer to a location where the return code will be stored + * @return SEMIHOSTING_HANDLED if a request was processed or SEMIHOSTING_NONE with the proper retval + */ +int esp_xtensa_semihosting(struct target *target, int *retval) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + + xtensa_reg_val_t dbg_cause = xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); + if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0) + return SEMIHOSTING_NONE; + + uint8_t brk_insn_buf[sizeof(uint32_t)] = { 0 }; + xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); + *retval = target_read_memory(target, pc, ESP_XTENSA_SYSCALL_SZ, 1, brk_insn_buf); + if (*retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read break instruction!"); + return SEMIHOSTING_NONE; + } + + uint32_t syscall_ins = buf_get_u32(brk_insn_buf, 0, 32); + if (syscall_ins != ESP_XTENSA_SYSCALL) { + *retval = ERROR_OK; + return SEMIHOSTING_NONE; + } + + if (esp_xtensa->semihost.ops && esp_xtensa->semihost.ops->prepare) + esp_xtensa->semihost.ops->prepare(target); + + xtensa_reg_val_t a2 = xtensa_reg_get(target, XT_REG_IDX_A2); + xtensa_reg_val_t a3 = xtensa_reg_get(target, XT_REG_IDX_A3); + LOG_TARGET_DEBUG(target, "Semihosting call 0x%" PRIx32 " 0x%" PRIx32 " Base dir '%s'", + a2, + a3, + target->semihosting->basedir ? target->semihosting->basedir : ""); + + target->semihosting->op = a2; + target->semihosting->param = a3; + + *retval = semihosting_common(target); + + /* Most operations are resumable, except the two exit calls. */ + if (*retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Semihosting operation (op: 0x%x) error! Code: %d", + target->semihosting->op, + *retval); + } + + /* Resume if target it is resumable and we are not waiting on a fileio operation to complete. */ + if (target->semihosting->is_resumable && !target->semihosting->hit_fileio) + target_to_esp_xtensa(target)->semihost.need_resume = true; + + return SEMIHOSTING_HANDLED; +} + +static int xtensa_semihosting_init(struct target *target) +{ + return semihosting_common_init(target, esp_xtensa_semihosting_setup, esp_xtensa_semihosting_post_result); +} + +int esp_xtensa_semihosting_init(struct target *target) +{ + int retval = xtensa_semihosting_init(target); + if (retval != ERROR_OK) + return retval; + target->semihosting->word_size_bytes = 4; /* 32 bits */ + target->semihosting->user_command_extension = esp_semihosting_common; + return ERROR_OK; +} diff --git a/src/target/espressif/esp_xtensa_semihosting.h b/src/target/espressif/esp_xtensa_semihosting.h new file mode 100644 index 000000000..1da311579 --- /dev/null +++ b/src/target/espressif/esp_xtensa_semihosting.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H +#define OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H + +#include + +int esp_xtensa_semihosting_init(struct target *target); +int esp_xtensa_semihosting(struct target *target, int *retval); + +#endif /* OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H */ diff --git a/src/target/espressif/esp_xtensa_smp.c b/src/target/espressif/esp_xtensa_smp.c index b109f3c5e..235a86eb9 100644 --- a/src/target/espressif/esp_xtensa_smp.c +++ b/src/target/espressif/esp_xtensa_smp.c @@ -13,7 +13,9 @@ #include #include #include +#include #include "esp_xtensa_smp.h" +#include "esp_xtensa_semihosting.h" /* Multiprocessor stuff common: @@ -128,6 +130,7 @@ int esp_xtensa_smp_poll(struct target *target) { enum target_state old_state = target->state; struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); struct target_list *head; struct target *curr; bool other_core_resume_req = false; @@ -180,6 +183,19 @@ int esp_xtensa_smp_poll(struct target *target) if (old_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { + if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) { + if (ret == ERROR_OK && esp_xtensa->semihost.need_resume && + !esp_xtensa_smp->other_core_does_resume) { + esp_xtensa->semihost.need_resume = false; + /* Resume xtensa_resume will handle BREAK instruction. */ + ret = target_resume(target, 1, 0, 1, 0); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return ret; + } + } + return ret; + } /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */ if (target->smp && other_core_resume_req) { /* Resume xtensa_resume will handle BREAK instruction. */ @@ -253,6 +269,11 @@ static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resu if (ret != ERROR_OK) return ret; esp_xtensa_smp->other_core_does_resume = false; + struct esp_xtensa_common *curr_esp_xtensa = target_to_esp_xtensa(curr); + if (curr_esp_xtensa->semihost.need_resume) { + curr_esp_xtensa->semihost.need_resume = false; + *need_resume = true; + } } /* after all targets were updated, poll the gdb serving target */ @@ -451,9 +472,10 @@ int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *w int esp_xtensa_smp_init_arch_info(struct target *target, struct esp_xtensa_smp_common *esp_xtensa_smp, struct xtensa_debug_module_config *dm_cfg, - const struct esp_xtensa_smp_chip_ops *chip_ops) + const struct esp_xtensa_smp_chip_ops *chip_ops, + const struct esp_semihost_ops *semihost_ops) { - int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg); + int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg, semihost_ops); if (ret != ERROR_OK) return ret; esp_xtensa_smp->chip_ops = chip_ops; @@ -463,7 +485,24 @@ int esp_xtensa_smp_init_arch_info(struct target *target, int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target) { - return esp_xtensa_target_init(cmd_ctx, target); + int ret = esp_xtensa_target_init(cmd_ctx, target); + if (ret != ERROR_OK) + return ret; + + if (target->smp) { + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + ret = esp_xtensa_semihosting_init(curr); + if (ret != ERROR_OK) + return ret; + } + } else { + ret = esp_xtensa_semihosting_init(target); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef) diff --git a/src/target/espressif/esp_xtensa_smp.h b/src/target/espressif/esp_xtensa_smp.h index bafd42066..aeb1d61f5 100644 --- a/src/target/espressif/esp_xtensa_smp.h +++ b/src/target/espressif/esp_xtensa_smp.h @@ -44,7 +44,8 @@ int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *t int esp_xtensa_smp_init_arch_info(struct target *target, struct esp_xtensa_smp_common *esp_xtensa_smp, struct xtensa_debug_module_config *dm_cfg, - const struct esp_xtensa_smp_chip_ops *chip_ops); + const struct esp_xtensa_smp_chip_ops *chip_ops, + const struct esp_semihost_ops *semihost_ops); extern const struct command_registration esp_xtensa_smp_command_handlers[]; extern const struct command_registration esp_xtensa_smp_xtensa_command_handlers[]; diff --git a/tcl/target/esp32.cfg b/tcl/target/esp32.cfg index 4206080ac..f4c13aa5b 100644 --- a/tcl/target/esp32.cfg +++ b/tcl/target/esp32.cfg @@ -3,6 +3,9 @@ # The ESP32 only supports JTAG. transport select jtag +# Source the ESP common configuration file +source [find target/esp_common.cfg] + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { @@ -67,6 +70,30 @@ if { $_ONLYCPU != 1 } { $_TARGETNAME_1 configure -event reset-assert-post { soft_reset_halt } } +$_TARGETNAME_0 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } +} + +if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } + } +} + gdb_breakpoint_override hard source [find target/xtensa-core-esp32.cfg] diff --git a/tcl/target/esp32s2.cfg b/tcl/target/esp32s2.cfg index 23ada5e9b..e478a6d39 100644 --- a/tcl/target/esp32s2.cfg +++ b/tcl/target/esp32s2.cfg @@ -7,6 +7,8 @@ set CPU_MAX_ADDRESS 0xFFFFFFFF source [find bitsbytes.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] +# Source the ESP common configuration file +source [find target/esp_common.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -60,6 +62,17 @@ $_TARGETNAME configure -event gdb-attach { xtensa maskisr on +$_TARGETNAME configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } +} + $_TARGETNAME configure -event reset-assert-post { soft_reset_halt } gdb_breakpoint_override hard diff --git a/tcl/target/esp32s3.cfg b/tcl/target/esp32s3.cfg index a25dc145c..42b219963 100644 --- a/tcl/target/esp32s3.cfg +++ b/tcl/target/esp32s3.cfg @@ -7,6 +7,9 @@ set CPU_MAX_ADDRESS 0xFFFFFFFF source [find bitsbytes.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] +# Source the ESP common configuration file +source [find target/esp_common.cfg] + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -96,6 +99,29 @@ if { $_ONLYCPU != 1 } { $_TARGETNAME_0 xtensa maskisr on $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut +$_TARGETNAME_0 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } +} + +if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } + } +} $_TARGETNAME_0 configure -event gdb-attach { $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut diff --git a/tcl/target/esp_common.cfg b/tcl/target/esp_common.cfg new file mode 100644 index 000000000..424c0cdff --- /dev/null +++ b/tcl/target/esp_common.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Common ESP chips definitions + +if { [info exists ESP_SEMIHOST_BASEDIR] } { + set _SEMIHOST_BASEDIR $ESP_SEMIHOST_BASEDIR +} else { + # by default current dir (when OOCD has been started) + set _SEMIHOST_BASEDIR "." +} -- 2.30.2