-/* SPDX-License-Identifier: GPL-2.0-or-later */
+// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* ESP Xtensa SMP target API for OpenOCD *
#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:
return ERROR_OK;
}
+int esp_xtensa_smp_on_halt(struct target *target)
+{
+ struct target_list *head;
+
+ if (!target->smp)
+ return esp_xtensa_on_halt(target);
+
+ foreach_smp_target(head, target->smp_targets) {
+ int res = esp_xtensa_on_halt(head->target);
+ if (res != ERROR_OK)
+ return res;
+ }
+ return ERROR_OK;
+}
+
static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
{
struct target_list *head;
{
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;
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. */
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 */
int esp_xtensa_smp_init_arch_info(struct target *target,
struct esp_xtensa_smp_common *esp_xtensa_smp,
- const struct xtensa_config *xtensa_cfg,
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, xtensa_cfg, 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;
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)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
+ target_to_xtensa(target));
}
COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
}
const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = {
+ {
+ .name = "xtdef",
+ .handler = esp_xtensa_smp_cmd_xtdef,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa core type",
+ .usage = "<type>",
+ },
+ {
+ .name = "xtopt",
+ .handler = esp_xtensa_smp_cmd_xtopt,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa core option",
+ .usage = "<name> <value>",
+ },
+ {
+ .name = "xtmem",
+ .handler = esp_xtensa_smp_cmd_xtmem,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa memory/cache option",
+ .usage = "<type> [parameters]",
+ },
+ {
+ .name = "xtmmu",
+ .handler = esp_xtensa_smp_cmd_xtmmu,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa MMU option",
+ .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>",
+ },
+ {
+ .name = "xtmpu",
+ .handler = esp_xtensa_smp_cmd_xtmpu,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa MPU option",
+ .usage = "<num FG seg> <min seg size> <lockable> <executeonly>",
+ },
+ {
+ .name = "xtreg",
+ .handler = esp_xtensa_smp_cmd_xtreg,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa register",
+ .usage = "<regname> <regnum>",
+ },
+ {
+ .name = "xtregs",
+ .handler = esp_xtensa_smp_cmd_xtreg,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure number of Xtensa registers",
+ .usage = "<numregs>",
+ },
+ {
+ .name = "xtregfmt",
+ .handler = esp_xtensa_smp_cmd_xtregfmt,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure format of Xtensa register map",
+ .usage = "<numgregs>",
+ },
{
.name = "set_permissive",
.handler = esp_xtensa_smp_cmd_permissive_mode,