From 2d4c53b3383b1a1a326c1e6c7e36a6547f62054d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 20 Jun 2023 09:20:33 -0700 Subject: [PATCH 01/10] jtag/drivers/xds110: Initialize `written` Otherwise I get a compiler warning, which fails the build. Change-Id: Ib7d4ab85160b537d07c74f8651ac42906fd661ed Signed-off-by: Tim Newsome --- src/jtag/drivers/xds110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 8e5d638db..47d06f1d8 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -579,7 +579,7 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) static bool usb_send_command(uint16_t size) { - int written; + int written = 0; bool success = true; /* Check the packet length */ From 2a64da39b09626957fa776d16517bda243f0b23a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 2 Jun 2023 15:19:26 -0700 Subject: [PATCH 02/10] target/riscv: Remove unused riscv013_on_halt function The riscv013_on_halt function was being called but its implementation was empty, providing no additional functionality. Removed the function declaration, calls to it, and its implementation since it is not required. Change-Id: I425ea890deadeec945f0a47af247f3f99172e801 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 7 ------- src/target/riscv/riscv.c | 3 --- src/target/riscv/riscv.h | 1 - 3 files changed, 11 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 35b7c9a6d..7c1d055b2 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -44,7 +44,6 @@ static int riscv013_halt_prep(struct target *target); static int riscv013_halt_go(struct target *target); static int riscv013_resume_go(struct target *target); static int riscv013_step_current_hart(struct target *target); -static int riscv013_on_halt(struct target *target); static int riscv013_on_step(struct target *target); static int riscv013_resume_prep(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); @@ -2476,7 +2475,6 @@ static int init_target(struct command_context *cmd_ctx, generic_info->get_hart_state = &riscv013_get_hart_state; generic_info->resume_go = &riscv013_resume_go; generic_info->step_current_hart = &riscv013_step_current_hart; - generic_info->on_halt = &riscv013_on_halt; generic_info->resume_prep = &riscv013_resume_prep; generic_info->halt_prep = &riscv013_halt_prep; generic_info->halt_go = &riscv013_halt_go; @@ -4502,11 +4500,6 @@ static int riscv013_on_step(struct target *target) return riscv013_on_step_or_resume(target, true); } -static int riscv013_on_halt(struct target *target) -{ - return ERROR_OK; -} - static enum riscv_halt_reason riscv013_halt_reason(struct target *target) { riscv_reg_t dcsr; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a6cfbc6a6..8927ac136 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2752,8 +2752,6 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a } } - r->on_halt(target); - /* We shouldn't do the callbacks yet. What if * there are multiple harts that halted at the * same time? We need to set debug reason on each @@ -4538,7 +4536,6 @@ static int riscv_step_rtos_hart(struct target *target) r->on_step(target); if (r->step_current_hart(target) != ERROR_OK) return ERROR_FAIL; - r->on_halt(target); if (target->state != TARGET_HALTED) { LOG_ERROR("Hart was not halted after single step!"); return ERROR_FAIL; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 9669e323a..a695cc349 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -193,7 +193,6 @@ struct riscv_info { * was resumed. */ int (*resume_go)(struct target *target); int (*step_current_hart)(struct target *target); - int (*on_halt)(struct target *target); /* Get this target as ready as possible to resume, without actually * resuming. */ int (*resume_prep)(struct target *target); From 866282ba9ec812c99d9de885ee3314c19b329e51 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 2 Jun 2023 16:10:54 -0700 Subject: [PATCH 03/10] target/riscv: Add debug msg to reset_delays_wait Makes it easier when reading debug logs. Change-Id: I3938437357e0d74e1cda680693f907a20c5579c7 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 7c1d055b2..69180a6cf 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -474,6 +474,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, if (r->reset_delays_wait >= 0) { r->reset_delays_wait--; if (r->reset_delays_wait < 0) { + LOG_TARGET_DEBUG(target, "reset_delays_wait done"); info->dmi_busy_delay = 0; info->ac_busy_delay = 0; } From 9d8bbb559d86a4fdca89111f87f01d9973013eee Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 2 Jun 2023 16:13:37 -0700 Subject: [PATCH 04/10] target/riscv: Tweak set_group(). Make it callable earlier, handle `supported` being NULL, and make enum names more clear. Change-Id: If4d286b54ccfc01eb5de5a57eb18f748c920e979 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 69180a6cf..7c7ca1968 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -67,6 +67,13 @@ static int read_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); +typedef enum { + HALT_GROUP, + RESUME_GROUP +} grouptype_t; +static int set_group(struct target *target, bool *supported, unsigned int group, + grouptype_t grouptype); + /** * Since almost everything can be accomplish by scanning the dbus register, all * functions here assume dbus is already selected. The exception are functions @@ -1591,22 +1598,20 @@ static void deinit_target(struct target *target) info->version_specific = NULL; } -typedef enum { - HALTGROUP, - RESUMEGROUP -} grouptype_t; -static int set_group(struct target *target, bool *supported, unsigned group, grouptype_t grouptype) +static int set_group(struct target *target, bool *supported, unsigned int group, + grouptype_t grouptype) { uint32_t write_val = DM_DMCS2_HGWRITE; assert(group <= 31); write_val = set_field(write_val, DM_DMCS2_GROUP, group); - write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALTGROUP) ? 0 : 1); + write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALT_GROUP) ? 0 : 1); if (dmi_write(target, DM_DMCS2, write_val) != ERROR_OK) return ERROR_FAIL; uint32_t read_val; if (dmi_read(target, &read_val, DM_DMCS2) != ERROR_OK) return ERROR_FAIL; - *supported = get_field(read_val, DM_DMCS2_GROUP) == group; + if (supported) + *supported = (get_field(read_val, DM_DMCS2_GROUP) == group); return ERROR_OK; } @@ -1880,7 +1885,7 @@ static int examine(struct target *target) if (target->smp) { bool haltgroup_supported; - if (set_group(target, &haltgroup_supported, target->smp, HALTGROUP) != ERROR_OK) + if (set_group(target, &haltgroup_supported, target->smp, HALT_GROUP) != ERROR_OK) return ERROR_FAIL; if (haltgroup_supported) LOG_INFO("Core %d made part of halt group %d.", target->coreid, From b496bebcda5f79387c94f6dfb0d90db42f3412d8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 2 Jun 2023 16:20:07 -0700 Subject: [PATCH 05/10] target/riscv: Improve update_dcsr()->set_dcsr_ebreak() * Only set ebreak bits that might be supported based on misa. * Don't write dcsr if its value wouldn't change. Change-Id: I7087af0b0df0fbdbf994373b5c887b9b389df872 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 7c7ca1968..9f218e4b5 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1563,23 +1563,26 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) return ERROR_OK; } -static int update_dcsr(struct target *target, bool step) +static int set_dcsr_ebreak(struct target *target, bool step) { + LOG_TARGET_DEBUG(target, "Set dcsr.ebreak*"); + if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; - riscv_reg_t dcsr; + riscv_reg_t original_dcsr, dcsr; /* We want to twiddle some bits in the debug CSR so debugging works. */ - int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); - if (result != ERROR_OK) - return result; + if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + original_dcsr = dcsr; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, riscv_ebreaku); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, riscv_ebreaku); - if (riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks && riscv_supports_extension(target, 'S')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku && riscv_supports_extension(target, 'U')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, riscv_ebreaku && riscv_supports_extension(target, 'H')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, riscv_ebreaku && riscv_supports_extension(target, 'H')); + if (dcsr != original_dcsr && + riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } @@ -1871,7 +1874,7 @@ static int examine(struct target *target) if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; - if (update_dcsr(target, false) != ERROR_OK) + if (set_dcsr_ebreak(target, false) != ERROR_OK) return ERROR_FAIL; target->state = saved_tgt_state; @@ -4629,7 +4632,7 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (maybe_execute_fence_i(target) != ERROR_OK) return ERROR_FAIL; - if (update_dcsr(target, step) != ERROR_OK) + if (set_dcsr_ebreak(target, step) != ERROR_OK) return ERROR_FAIL; if (riscv_flush_registers(target) != ERROR_OK) From 6e64b685f49f8fdd54485cec323fdb6ed09090c0 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 5 Jun 2023 10:28:41 -0700 Subject: [PATCH 06/10] target/riscv: Track whether halt groups are supported. Will be used later when we want to do a quick halt/resume. Change-Id: Ib80166234c4c277b7d9ce26b7566ac0f93017e64 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 9f218e4b5..b4f6799a4 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -205,6 +205,9 @@ typedef struct { /* This target was selected using hasel. */ bool selected; + + /* This hart was placed into a halt group in examine(). */ + bool haltgroup_supported; } riscv013_info_t; static LIST_HEAD(dm_list); @@ -1890,7 +1893,7 @@ static int examine(struct target *target) bool haltgroup_supported; if (set_group(target, &haltgroup_supported, target->smp, HALT_GROUP) != ERROR_OK) return ERROR_FAIL; - if (haltgroup_supported) + if (info->haltgroup_supported) LOG_INFO("Core %d made part of halt group %d.", target->coreid, target->smp); else From 34f9ff0d0d86b9616fb620a07f3d5bafeaf75338 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 5 Jun 2023 10:39:12 -0700 Subject: [PATCH 07/10] target/riscv: Add some event callbacks. Specifically, call into the RISC-V version when target becomes halted, running, or unavailable. I'll be using unavailable shortly. Change-Id: I9ffffdccbf22e053fe6390d656b362bf9ab9559a Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 10 ++++++++++ src/target/riscv/riscv.h | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8927ac136..a5b7dcf75 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2752,6 +2752,10 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a } } + if (r->handle_became_halted && + r->handle_became_halted(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; + /* We shouldn't do the callbacks yet. What if * there are multiple harts that halted at the * same time? We need to set debug reason on each @@ -2769,12 +2773,18 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a LOG_TARGET_DEBUG(target, " triggered running"); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; + if (r->handle_became_running && + r->handle_became_running(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; break; case RISCV_STATE_UNAVAILABLE: LOG_TARGET_DEBUG(target, " became unavailable"); LOG_TARGET_INFO(target, "became unavailable."); target->state = TARGET_UNAVAILABLE; + if (r->handle_became_unavailable && + r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; break; case RISCV_STATE_NON_EXISTENT: diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index a695cc349..03159cfa2 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -193,6 +193,17 @@ struct riscv_info { * was resumed. */ int (*resume_go)(struct target *target); int (*step_current_hart)(struct target *target); + + /* These get called from riscv_poll_hart(), which is a house of cards + * together with openocd_poll(), so be careful not to upset things too + * much. */ + int (*handle_became_halted)(struct target *target, + enum riscv_hart_state previous_riscv_state); + int (*handle_became_running)(struct target *target, + enum riscv_hart_state previous_riscv_state); + int (*handle_became_unavailable)(struct target *target, + enum riscv_hart_state previous_riscv_state); + /* Get this target as ready as possible to resume, without actually * resuming. */ int (*resume_prep)(struct target *target); From 87bfe9f50587933c0aa3fbf1fc6632f34d77cb54 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 5 Jun 2023 10:43:05 -0700 Subject: [PATCH 08/10] target/riscv: Add periodic tick() callback Intended as a place where we can interact with the target without too much concern about preserving state and doing exactly the right thing while poll() is going on. Change-Id: Ic9bd441caae85901a131fd45e742599803df89b5 Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 11 +++++++++++ src/target/riscv/riscv.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a5b7dcf75..1aaf50587 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2934,6 +2934,17 @@ int riscv_openocd_poll(struct target *target) } } + /* Call tick() for every hart. What happens in tick() is opaque to this + * layer. The reason it's outside the previous loop is that at this point + * the state of every hart has settled, so any side effects happening in + * tick() won't affect the delicate poll() code. */ + foreach_smp_target(entry, targets) { + struct target *t = entry->target; + struct riscv_info *info = riscv_info(t); + if (info->tick && info->tick(t) != ERROR_OK) + return ERROR_FAIL; + } + /* Sample memory if any target is running. */ foreach_smp_target(entry, targets) { struct target *t = entry->target; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 03159cfa2..4cbe00612 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -204,6 +204,10 @@ struct riscv_info { int (*handle_became_unavailable)(struct target *target, enum riscv_hart_state previous_riscv_state); + /* Called periodically (no guarantees about frequency), while there's + * nothing else going on. */ + int (*tick)(struct target *target); + /* Get this target as ready as possible to resume, without actually * resuming. */ int (*resume_prep)(struct target *target); From da5bf318b974ba9e7d1e5c2c24f9f070740fd5f8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 5 Jun 2023 10:48:27 -0700 Subject: [PATCH 09/10] target/riscv: Track whether ebreak* is set. We need to know, so we can set it when necessary. Change-Id: I1f0d5107f1208f7b9316e15870f0804e51232dee Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index b4f6799a4..b542a102d 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -206,6 +206,10 @@ typedef struct { /* This target was selected using hasel. */ bool selected; + /* When false, we need to set dcsr.ebreak*, halting the target if that's + * necessary. */ + bool dcsr_ebreak_is_set; + /* This hart was placed into a halt group in examine(). */ bool haltgroup_supported; } riscv013_info_t; @@ -1573,6 +1577,7 @@ static int set_dcsr_ebreak(struct target *target, bool step) if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; + RISCV013_INFO(info); riscv_reg_t original_dcsr, dcsr; /* We want to twiddle some bits in the debug CSR so debugging works. */ if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) @@ -1587,6 +1592,7 @@ static int set_dcsr_ebreak(struct target *target, bool step) if (dcsr != original_dcsr && riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; + info->dcsr_ebreak_is_set = true; return ERROR_OK; } @@ -2440,6 +2446,7 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state return ERROR_FAIL; if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); + info->dcsr_ebreak_is_set = false; /* TODO: Can we make this more obvious to eg. a gdb user? */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET; @@ -2473,6 +2480,14 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state return ERROR_FAIL; } +static int handle_became_unavailable(struct target *target, + enum riscv_hart_state previous_riscv_state) +{ + RISCV013_INFO(info); + info->dcsr_ebreak_is_set = false; + return ERROR_OK; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -2508,6 +2523,9 @@ static int init_target(struct command_context *cmd_ctx, generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; + + generic_info->handle_became_unavailable = &handle_became_unavailable; + if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) @@ -2625,6 +2643,7 @@ static int deassert_reset(struct target *target) target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } + info->dcsr_ebreak_is_set = false; /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ control = 0; From bf07ddef8a012961501faa136d3f574ae89ccf7e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 5 Jun 2023 10:50:15 -0700 Subject: [PATCH 10/10] target/riscv: From tick(), set ebreak* if necessary. This involves halting the target, which might have unintended side effects, but when the debugger is connected software breakpoints must trap to the debugger. Anything else is a terrible user experience. Change-Id: I1f7bb610eeeb054cc3042dc6bcfc16589ce12a31 Signed-off-by: Tim Newsome --- src/target/riscv/riscv-013.c | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index b542a102d..1e8a389fe 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1596,6 +1596,69 @@ static int set_dcsr_ebreak(struct target *target, bool step) return ERROR_OK; } +static int halt_set_dcsr_ebreak(struct target *target) +{ + RISCV_INFO(r); + RISCV013_INFO(info); + LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*"); + + /* Remove this hart from the halt group. This won't work on all targets + * because the debug spec allows halt groups to be hard-coded, but I + * haven't actually encountered those in the wild yet. + * + * There is a possible race condition when another hart halts, and + * this one is expected to also halt because it's supposed to be in the + * same halt group. Or when this hart is halted when that happens. + * + * A better solution might be to leave the halt groups alone, and track + * why we're halting when a halt occurs. When there are halt groups, + * that leads to extra halting if not all harts need to set dcsr.ebreak + * at the same time. It also makes for more complicated code. + * + * The perfect solution would be Quick Access, but I'm not aware of any + * hardware that implements it. + * + * We don't need a perfect solution, because we only get here when a + * hart spontaneously resets, or when it powers down and back up again. + * Those are both relatively rare. (At least I hope so. Maybe some + * design just powers each hart down for 90ms out of every 100ms) + */ + + + if (info->haltgroup_supported) { + bool supported; + if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK) + return ERROR_FAIL; + if (!supported) + LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. " + "Some harts may be unexpectedly halted."); + } + + int result = ERROR_OK; + + r->prepped = true; + if (riscv013_halt_go(target) != ERROR_OK || + set_dcsr_ebreak(target, false) != ERROR_OK || + riscv013_step_or_resume_current_hart(target, false) != ERROR_OK) { + result = ERROR_FAIL; + } else { + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + + /* Add it back to the halt group. */ + if (info->haltgroup_supported) { + bool supported; + if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK) + return ERROR_FAIL; + if (!supported) + LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. " + "Some harts may be unexpectedly halted.", target->smp); + } + + return result; +} + /*** OpenOCD target functions. ***/ static void deinit_target(struct target *target) @@ -2488,6 +2551,16 @@ static int handle_became_unavailable(struct target *target, return ERROR_OK; } +static int tick(struct target *target) +{ + RISCV013_INFO(info); + if (!info->dcsr_ebreak_is_set && + target->state == TARGET_RUNNING && + target_was_examined(target)) + return halt_set_dcsr_ebreak(target); + return ERROR_OK; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -2525,6 +2598,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->print_info = &riscv013_print_info; generic_info->handle_became_unavailable = &handle_became_unavailable; + generic_info->tick = &tick; if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));