target/espressif: add semihosting support 74/7074/8
authorErhan Kurubas <erhan.kurubas@espressif.com>
Thu, 30 Jun 2022 10:14:27 +0000 (13:14 +0300)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 3 Sep 2022 21:27:17 +0000 (21:27 +0000)
ARM semihosting + some custom syscalls implemented for
Espressif chips (ESP32, ESP32-S2, ESP32-S3)

Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>
Change-Id: Ic8174cf1cd344fa16d619b7b8405c9650e869443
Reviewed-on: https://review.openocd.org/c/openocd/+/7074
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
16 files changed:
src/target/espressif/Makefile.am
src/target/espressif/esp32.c
src/target/espressif/esp32s2.c
src/target/espressif/esp32s3.c
src/target/espressif/esp_semihosting.c [new file with mode: 0644]
src/target/espressif/esp_semihosting.h [new file with mode: 0644]
src/target/espressif/esp_xtensa.c
src/target/espressif/esp_xtensa.h
src/target/espressif/esp_xtensa_semihosting.c [new file with mode: 0644]
src/target/espressif/esp_xtensa_semihosting.h [new file with mode: 0644]
src/target/espressif/esp_xtensa_smp.c
src/target/espressif/esp_xtensa_smp.h
tcl/target/esp32.cfg
tcl/target/esp32s2.cfg
tcl/target/esp32s3.cfg
tcl/target/esp_common.cfg [new file with mode: 0644]

index 1b4f8062e31a08bd7dacb16b24b028f58f02357a..8367a3881931e4107e74c3abaa11468c1c3226e7 100644 (file)
@@ -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
index a083627fbcfa042263afe04b37fd7024977c6af5..8ad8bad8351056c60561cb582f9dea9d27565dc9 100644 (file)
@@ -13,6 +13,7 @@
 #include <target/target.h>
 #include <target/target_type.h>
 #include <target/smp.h>
+#include <target/semihosting_common.h>
 #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
 };
 
index 0bcd20f2d22ad3e92e4c616fc0978adc94702c7c..4aef3791bf67ccf05a0b8dbddf857043a1ef2f20 100644 (file)
@@ -13,7 +13,9 @@
 #include "assert.h"
 #include <target/target.h>
 #include <target/target_type.h>
+#include <target/semihosting_common.h>
 #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
 };
 
index b870059017de01dbc16429a940debb972f9a89f5..0da8552a35abb4a2e52500689c2ca940fd35e5db 100644 (file)
@@ -13,6 +13,7 @@
 #include <target/target.h>
 #include <target/target_type.h>
 #include <target/smp.h>
+#include <target/semihosting_common.h>
 #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 (file)
index 0000000..b1edef3
--- /dev/null
@@ -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 <helper/log.h>
+#include <target/target.h>
+#include <target/semihosting_common.h>
+#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 (file)
index 0000000..bd2c079
--- /dev/null
@@ -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 */
index fcd42eac30b91b50808f6c0e5a13314e7cc1257d..6a1b72ec48f70ba305063508d892b0611726c701 100644 (file)
 #include <stdbool.h>
 #include <stdint.h>
 #include <target/smp.h>
-#include "esp_xtensa.h"
 #include <target/register.h>
+#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)
index 61e87c086d068d286859f47b3dd7097c029c320b..1ad6c377f038f635acffe513f31534738051c416 100644 (file)
@@ -8,12 +8,14 @@
 #ifndef OPENOCD_TARGET_ESP_XTENSA_H
 #define OPENOCD_TARGET_ESP_XTENSA_H
 
-#include <helper/command.h>
 #include <target/target.h>
 #include <target/xtensa/xtensa.h>
+#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 (file)
index 0000000..9ea8e4d
--- /dev/null
@@ -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 <target/semihosting_common.h>
+#include <target/xtensa/xtensa_regs.h>
+#include <target/xtensa/xtensa.h>
+#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 (file)
index 0000000..1da3115
--- /dev/null
@@ -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 <target/target.h>
+
+int esp_xtensa_semihosting_init(struct target *target);
+int esp_xtensa_semihosting(struct target *target, int *retval);
+
+#endif /* OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H */
index b109f3c5e9bad54108d2f7ee8ebd49c748c7d29b..235a86eb9d9019e0223d6826546e208adf4c11c0 100644 (file)
@@ -13,7 +13,9 @@
 #include <target/target.h>
 #include <target/target_type.h>
 #include <target/smp.h>
+#include <target/semihosting_common.h>
 #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)
index bafd4206672b01fbc4c799251163b32e1ede74a2..aeb1d61f58c764485be1ecc4bce6596a4cd09cba 100644 (file)
@@ -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[];
index 4206080acb7f4fdc628f830709f75e03169be17c..f4c13aa5b97f247b3c3899d3e452e3a504dcf31c 100644 (file)
@@ -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]
index 23ada5e9b0cc180f7eb84d2cc4c123fbb1683007..e478a6d39d52950442ef3af76ca0bf62ccb61b03 100644 (file)
@@ -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
index a25dc145c5f37cdb1b1063bea9a9bdcb33649dbb..42b2199633b54a7f8460a42fc62f701db3c174de 100644 (file)
@@ -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 (file)
index 0000000..424c0cd
--- /dev/null
@@ -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 "."
+}

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)