diff options
-rw-r--r-- | src/rtos/riscv_debug.c | 2 | ||||
-rw-r--r-- | src/target/riscv/riscv-011.c | 33 | ||||
-rw-r--r-- | src/target/riscv/riscv-013.c | 174 | ||||
-rw-r--r-- | src/target/riscv/riscv.c | 260 | ||||
-rw-r--r-- | src/target/riscv/riscv.h | 22 |
5 files changed, 300 insertions, 191 deletions
diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index 4695e4e..726f326 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -259,7 +259,7 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet, target_call_event_callbacks(target, TARGET_EVENT_GDB_START); target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); riscv_set_all_rtos_harts(target); - riscv_openocd_resume(target, 1, 0, 0, 0); + riscv_resume(target, 1, 0, 0, 0); target->state = TARGET_RUNNING; gdb_set_frontend_state_running(connection); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index eded862..aad5b8b 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -204,7 +204,6 @@ typedef struct { * before the interrupt is cleared. */ unsigned int interrupt_high_delay; - bool need_strict_step; bool never_halted; } riscv011_info_t; @@ -1413,8 +1412,6 @@ static void deinit_target(struct target *target) static int strict_step(struct target *target, bool announce) { - riscv011_info_t *info = get_info(target); - LOG_DEBUG("enter"); struct watchpoint *watchpoint = target->watchpoints; @@ -1433,16 +1430,12 @@ static int strict_step(struct target *target, bool announce) watchpoint = watchpoint->next; } - info->need_strict_step = false; - return ERROR_OK; } static int step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { - riscv011_info_t *info = get_info(target); - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); if (!current) { @@ -1455,7 +1448,7 @@ static int step(struct target *target, int current, target_addr_t address, return result; } - if (info->need_strict_step || handle_breakpoints) { + if (handle_breakpoints) { int result = strict_step(target, true); if (result != ERROR_OK) return result; @@ -1486,7 +1479,6 @@ static int examine(struct target *target) } RISCV_INFO(r); - r->hart_count = 1; riscv011_info_t *info = get_info(target); info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS); @@ -1848,9 +1840,6 @@ static int handle_halt(struct target *target, bool announce) break; case DCSR_CAUSE_HWBP: target->debug_reason = DBG_REASON_WATCHPOINT; - /* If we halted because of a data trigger, gdb doesn't know to do - * the disable-breakpoints-step-enable-breakpoints dance. */ - info->need_strict_step = true; break; case DCSR_CAUSE_DEBUGINT: target->debug_reason = DBG_REASON_DBGRQ; @@ -1935,26 +1924,10 @@ static int riscv011_poll(struct target *target) static int riscv011_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { - riscv011_info_t *info = get_info(target); - + RISCV_INFO(r); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - if (!current) { - if (riscv_xlen(target) > 32) { - LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", - riscv_xlen(target)); - } - int result = register_write(target, GDB_REGNO_PC, address); - if (result != ERROR_OK) - return result; - } - - if (info->need_strict_step || handle_breakpoints) { - int result = strict_step(target, false); - if (result != ERROR_OK) - return result; - } - + r->prepped = false; return resume(target, debug_execution, false); } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1a5f212..d7bfac9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -32,7 +32,8 @@ #define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) static int riscv013_on_step_or_resume(struct target *target, bool step); -static int riscv013_step_or_resume_current_hart(struct target *target, bool step); +static int riscv013_step_or_resume_current_hart(struct target *target, + bool step, bool use_hasel); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ @@ -41,11 +42,11 @@ static int riscv013_get_register(struct target *target, static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); static int riscv013_select_current_hart(struct target *target); static int riscv013_halt_current_hart(struct target *target); -static int riscv013_resume_current_hart(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_on_resume(struct target *target); +static int riscv013_resume_prep(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); static int riscv013_write_debug_buffer(struct target *target, unsigned index, @@ -147,12 +148,16 @@ typedef enum { typedef struct { struct list_head list; int abs_chain_position; + + /* The number of harts connected to this DM. */ + int hart_count; /* Indicates we already reset this DM, so don't need to do it again. */ bool was_reset; /* Targets that are connected to this DM. */ struct list_head target_list; /* The currently selected hartid on this DM. */ int current_hartid; + bool hasel_supported; } dm013_info_t; typedef struct { @@ -161,6 +166,8 @@ typedef struct { } target_list_t; typedef struct { + /* The indexed used to address this hart in its DM. */ + unsigned index; /* Number of address bits in the dbus register. */ unsigned abits; /* Number of abstract command data registers. */ @@ -230,7 +237,7 @@ static riscv013_info_t *get_info(const struct target *target) * global list of DMs. If it's not in there, then create one and initialize it * to 0. */ -static dm013_info_t *get_dm(struct target *target) +dm013_info_t *get_dm(struct target *target) { RISCV013_INFO(info); if (info->dm) @@ -248,9 +255,11 @@ static dm013_info_t *get_dm(struct target *target) } if (!dm) { + LOG_DEBUG("[%d] Allocating new DM", target->coreid); dm = calloc(1, sizeof(dm013_info_t)); dm->abs_chain_position = abs_chain_position; dm->current_hartid = -1; + dm->hart_count = -1; INIT_LIST_HEAD(&dm->target_list); list_add(&dm->list, &dm_list); } @@ -1397,6 +1406,8 @@ static int examine(struct target *target) } riscv013_info_t *info = get_info(target); + /* TODO: This won't be true if there are multiple DMs. */ + info->index = target->coreid; info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcs_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); @@ -1409,7 +1420,8 @@ static int examine(struct target *target) } dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_HARTSELLO | - DMI_DMCONTROL_HARTSELHI | DMI_DMCONTROL_DMACTIVE); + DMI_DMCONTROL_HARTSELHI | DMI_DMCONTROL_DMACTIVE | + DMI_DMCONTROL_HASEL); uint32_t dmcontrol; if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) return ERROR_FAIL; @@ -1420,6 +1432,8 @@ static int examine(struct target *target) return ERROR_FAIL; } + dm->hasel_supported = get_field(dmcontrol, DMI_DMCONTROL_HASEL); + uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) return ERROR_FAIL; @@ -1483,10 +1497,35 @@ static int examine(struct target *target) } /* Before doing anything else we must first enumerate the harts. */ + if (dm->hart_count < 0) { + for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { + r->current_hartid = i; + if (riscv013_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + uint32_t s; + if (dmstatus_read(target, &s, true) != ERROR_OK) + return ERROR_FAIL; + if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) + break; + dm->hart_count = i + 1; + + if (get_field(s, DMI_DMSTATUS_ANYHAVERESET)) + dmi_write(target, DMI_DMCONTROL, + set_hartsel(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET, i)); + } + + LOG_DEBUG("Detected %d harts.", dm->hart_count); + } + + if (dm->hart_count == 0) { + LOG_ERROR("No harts found!"); + return ERROR_FAIL; + } /* Don't call any riscv_* functions until after we've counted the number of * cores and initialized registers. */ - for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { + for (int i = 0; i < dm->hart_count; ++i) { if (!riscv_rtos_enabled(target) && i != target->coreid) continue; @@ -1494,17 +1533,6 @@ static int examine(struct target *target) if (riscv013_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; - uint32_t s; - if (dmstatus_read(target, &s, true) != ERROR_OK) - return ERROR_FAIL; - if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) - break; - r->hart_count = i + 1; - - if (get_field(s, DMI_DMSTATUS_ANYHAVERESET)) - dmi_write(target, DMI_DMCONTROL, - set_hartsel(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET, i)); - bool halted = riscv_is_halted(target); if (!halted) { if (riscv013_halt_current_hart(target) != ERROR_OK) { @@ -1538,21 +1566,11 @@ static int examine(struct target *target) r->misa[i]); if (!halted) - riscv013_resume_current_hart(target); - } - - LOG_DEBUG("Enumerated %d harts", r->hart_count); - - if (r->hart_count == 0) { - LOG_ERROR("No harts found!"); - return ERROR_FAIL; + riscv013_step_or_resume_current_hart(target, false, false); } target_set_examined(target); - if (target->rtos) - riscv_update_threads(target->rtos); - if (target->smp) { bool haltgroup_supported; if (set_haltgroup(target, &haltgroup_supported) != ERROR_OK) @@ -1616,6 +1634,12 @@ int riscv013_authdata_write(struct target *target, uint32_t value) return ERROR_OK; } +static int riscv013_hart_count(struct target *target) +{ + dm013_info_t *dm = get_dm(target); + return dm->hart_count; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -1627,10 +1651,10 @@ static int init_target(struct command_context *cmd_ctx, generic_info->select_current_hart = &riscv013_select_current_hart; generic_info->is_halted = &riscv013_is_halted; generic_info->halt_current_hart = &riscv013_halt_current_hart; - generic_info->resume_current_hart = &riscv013_resume_current_hart; + 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->on_resume = &riscv013_on_resume; + generic_info->resume_prep = &riscv013_resume_prep; generic_info->on_step = &riscv013_on_step; generic_info->halt_reason = &riscv013_halt_reason; generic_info->read_debug_buffer = &riscv013_read_debug_buffer; @@ -1646,6 +1670,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->dmi_write = &dmi_write; generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg; generic_info->test_compliance = &riscv013_test_compliance; + generic_info->hart_count = &riscv013_hart_count; generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; @@ -2822,7 +2847,7 @@ struct target_type riscv013_target = { .poll = &riscv_openocd_poll, .halt = &riscv_openocd_halt, - .resume = &riscv_openocd_resume, + .resume = &riscv_resume, .step = &riscv_openocd_step, .assert_reset = assert_reset, @@ -2945,17 +2970,74 @@ static int riscv013_halt_current_hart(struct target *target) return ERROR_OK; } -static int riscv013_resume_current_hart(struct target *target) +/* Select all harts that were prepped and that are selectable, clearing the + * prepped flag on the harts that actually were selected. */ +static int select_prepped_harts(struct target *target, bool *use_hasel) +{ + dm013_info_t *dm = get_dm(target); + if (!dm->hasel_supported) { + RISCV_INFO(r); + r->prepped = false; + *use_hasel = false; + return ERROR_OK; + } + + assert(dm->hart_count); + unsigned hawindow_count = (dm->hart_count + 31) / 32; + uint32_t hawindow[hawindow_count]; + + memset(hawindow, 0, sizeof(uint32_t) * hawindow_count); + + target_list_t *entry; + unsigned total_selected = 0; + list_for_each_entry(entry, &dm->target_list, list) { + struct target *t = entry->target; + riscv_info_t *r = riscv_info(t); + riscv013_info_t *info = get_info(t); + unsigned index = info->index; + LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped); + if (r->prepped) { + hawindow[index / 32] |= 1 << (index % 32); + r->prepped = false; + total_selected++; + } + index++; + } + + /* Don't use hasel if we only need to talk to one hart. */ + if (total_selected <= 1) { + *use_hasel = false; + return ERROR_OK; + } + + for (unsigned i = 0; i < hawindow_count; i++) { + if (dmi_write(target, DMI_HAWINDOWSEL, i) != ERROR_OK) + return ERROR_FAIL; + if (dmi_write(target, DMI_HAWINDOW, hawindow[i]) != ERROR_OK) + return ERROR_FAIL; + } + + *use_hasel = true; + return ERROR_OK; +} + +static int riscv013_resume_go(struct target *target) { - return riscv013_step_or_resume_current_hart(target, false); + bool use_hasel = false; + if (!riscv_rtos_enabled(target)) { + if (select_prepped_harts(target, &use_hasel) != ERROR_OK) + return ERROR_FAIL; + } + + return riscv013_step_or_resume_current_hart(target, false, use_hasel); } static int riscv013_step_current_hart(struct target *target) { - return riscv013_step_or_resume_current_hart(target, true); + return riscv013_step_or_resume_current_hart(target, true, false); } -static int riscv013_on_resume(struct target *target) +static int riscv013_resume_prep(struct target *target) { return riscv013_on_step_or_resume(target, false); } @@ -3458,7 +3540,8 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } -static int riscv013_step_or_resume_current_hart(struct target *target, bool step) +static int riscv013_step_or_resume_current_hart(struct target *target, + bool step, bool use_hasel) { RISCV_INFO(r); LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); @@ -3467,13 +3550,15 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step return ERROR_FAIL; } - if (maybe_execute_fence_i(target) != ERROR_OK) - return ERROR_FAIL; - /* Issue the resume command, and then wait for the current hart to resume. */ - uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE; + uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_RESUMEREQ; + if (use_hasel) + dmcontrol |= DMI_DMCONTROL_HASEL; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); - dmi_write(target, DMI_DMCONTROL, dmcontrol | DMI_DMCONTROL_RESUMEREQ); + dmi_write(target, DMI_DMCONTROL, dmcontrol); + + dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HASEL, 0); + dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0); uint32_t dmstatus; for (size_t i = 0; i < 256; ++i) { @@ -3489,10 +3574,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step return ERROR_OK; } + dmi_write(target, DMI_DMCONTROL, dmcontrol); + LOG_ERROR("unable to resume hart %d", r->current_hartid); - if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) - return ERROR_FAIL; - LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; LOG_ERROR(" dmstatus =0x%08x", dmstatus); @@ -3604,7 +3688,7 @@ int riscv013_test_compliance(struct target *target) /* resumereq */ /* This bit is not actually readable according to the spec, so nothing to check.*/ - COMPLIANCE_MUST_PASS(riscv_resume_all_harts(target)); + COMPLIANCE_MUST_PASS(riscv_resume(target, true, 0, false, false)); /* Halt all harts again so the test can continue.*/ COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target)); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index e027d00..5cdcc01 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -199,6 +199,8 @@ range_t *expose_csr; /* Same, but for custom registers. */ range_t *expose_custom; +static int riscv_resume_go_all_harts(struct target *target); + static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; @@ -846,16 +848,116 @@ static int riscv_deassert_reset(struct target *target) return tt->deassert_reset(target); } +int riscv_resume_prep_all_harts(struct target *target) +{ + RISCV_INFO(r); + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + LOG_DEBUG("prep hart %d", i); + if (riscv_set_current_hartid(target, i) != ERROR_OK) + return ERROR_FAIL; + if (riscv_is_halted(target)) { + if (r->resume_prep(target) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_DEBUG(" hart %d requested resume, but was already resumed", i); + } + } + return ERROR_OK; +} -static int oldriscv_resume(struct target *target, int current, uint32_t address, - int handle_breakpoints, int debug_execution) +/** + * Get everything ready to resume. + */ +static int resume_prep(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) { - struct target_type *tt = get_target_type(target); - return tt->resume(target, current, address, handle_breakpoints, - debug_execution); + RISCV_INFO(r); + LOG_DEBUG("[%d]", target->coreid); + + if (!current) + riscv_set_register(target, GDB_REGNO_PC, address); + + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* To be able to run off a trigger, disable all the triggers, step, and + * then resume as usual. */ + struct watchpoint *watchpoint = target->watchpoints; + bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; + + int i = 0; + int result = ERROR_OK; + while (watchpoint && result == ERROR_OK) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); + trigger_temporarily_cleared[i] = watchpoint->set; + if (watchpoint->set) + result = riscv_remove_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + i++; + } + + if (result == ERROR_OK) + result = old_or_new_riscv_step(target, true, 0, false); + + watchpoint = target->watchpoints; + i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); + if (trigger_temporarily_cleared[i]) { + if (result == ERROR_OK) + result = riscv_add_watchpoint(target, watchpoint); + else + riscv_add_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result != ERROR_OK) + return result; + } + + if (r->is_halted) { + if (riscv_resume_prep_all_harts(target) != ERROR_OK) + return ERROR_FAIL; + } + + LOG_DEBUG("[%d] mark as prepped", target->coreid); + r->prepped = true; + + return ERROR_OK; } -static int old_or_new_riscv_resume( +/** + * Resume all the harts that have been prepped, as close to instantaneous as + * possible. + */ +static int resume_go(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + riscv_info_t *r = riscv_info(target); + int result; + if (r->is_halted == NULL) { + struct target_type *tt = get_target_type(target); + result = tt->resume(target, current, address, handle_breakpoints, + debug_execution); + } else { + result = riscv_resume_go_all_harts(target); + } + + return result; +} + +static int resume_finish(struct target *target) +{ + register_cache_invalidate(target->reg_cache); + + target->state = TARGET_RUNNING; + return target_call_event_callbacks(target, TARGET_EVENT_RESUMED); +} + +int riscv_resume( struct target *target, int current, target_addr_t address, @@ -863,31 +965,43 @@ static int old_or_new_riscv_resume( int debug_execution ){ LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); + int result = ERROR_OK; if (target->smp) { - struct target_list *targets = target->head; - int result = ERROR_OK; - while (targets) { - struct target *t = targets->target; - riscv_info_t *r = riscv_info(t); - if (r->is_halted == NULL) { - if (oldriscv_resume(t, current, address, handle_breakpoints, + for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target *t = tlist->target; + if (resume_prep(t, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + } + + for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target *t = tlist->target; + riscv_info_t *i = riscv_info(t); + if (i->prepped) { + if (resume_go(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; - } else { - if (riscv_openocd_resume(t, current, address, - handle_breakpoints, debug_execution) != ERROR_OK) - result = ERROR_FAIL; } - targets = targets->next; } - return result; + + for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target *t = tlist->target; + if (resume_finish(t) != ERROR_OK) + return ERROR_FAIL; + } + + } else { + if (resume_prep(target, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + if (resume_go(target, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + if (resume_finish(target) != ERROR_OK) + return ERROR_FAIL; } - RISCV_INFO(r); - if (r->is_halted == NULL) - return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution); - else - return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution); + return result; } static int riscv_select_current_hart(struct target *target) @@ -1064,7 +1178,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, /* Run algorithm */ LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); - if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) + if (riscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) return ERROR_FAIL; int64_t start = timeval_ms(); @@ -1348,68 +1462,6 @@ int riscv_openocd_halt(struct target *target) return result; } -int riscv_openocd_resume( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints, - int debug_execution) -{ - LOG_DEBUG("debug_reason=%d", target->debug_reason); - - if (!current) - riscv_set_register(target, GDB_REGNO_PC, address); - - if (target->debug_reason == DBG_REASON_WATCHPOINT) { - /* To be able to run off a trigger, disable all the triggers, step, and - * then resume as usual. */ - struct watchpoint *watchpoint = target->watchpoints; - bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; - - int i = 0; - int result = ERROR_OK; - while (watchpoint && result == ERROR_OK) { - LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); - trigger_temporarily_cleared[i] = watchpoint->set; - if (watchpoint->set) - result = riscv_remove_watchpoint(target, watchpoint); - watchpoint = watchpoint->next; - i++; - } - - if (result == ERROR_OK) - result = riscv_step_rtos_hart(target); - - watchpoint = target->watchpoints; - i = 0; - while (watchpoint) { - LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); - if (trigger_temporarily_cleared[i]) { - if (result == ERROR_OK) - result = riscv_add_watchpoint(target, watchpoint); - else - riscv_add_watchpoint(target, watchpoint); - } - watchpoint = watchpoint->next; - i++; - } - - if (result != ERROR_OK) - return result; - } - - int out = riscv_resume_all_harts(target); - if (out != ERROR_OK) { - LOG_ERROR("unable to resume all harts"); - return out; - } - - register_cache_invalidate(target->reg_cache); - target->state = TARGET_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - return out; -} - int riscv_openocd_step( struct target *target, int current, @@ -1963,7 +2015,7 @@ struct target_type riscv_target = { .poll = old_or_new_riscv_poll, .halt = old_or_new_riscv_halt, - .resume = old_or_new_riscv_resume, + .resume = riscv_resume, .step = old_or_new_riscv_step, .assert_reset = riscv_assert_reset, @@ -2040,34 +2092,28 @@ int riscv_halt_one_hart(struct target *target, int hartid) return result; } -int riscv_resume_all_harts(struct target *target) +static int riscv_resume_go_all_harts(struct target *target) { + RISCV_INFO(r); for (int i = 0; i < riscv_count_harts(target); ++i) { if (!riscv_hart_enabled(target, i)) continue; - riscv_resume_one_hart(target, i); + LOG_DEBUG("resuming hart %d", i); + if (riscv_set_current_hartid(target, i) != ERROR_OK) + return ERROR_FAIL; + if (riscv_is_halted(target)) { + if (r->resume_go(target) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_DEBUG(" hart %d requested resume, but was already resumed", i); + } } riscv_invalidate_register_cache(target); return ERROR_OK; } -int riscv_resume_one_hart(struct target *target, int hartid) -{ - RISCV_INFO(r); - LOG_DEBUG("resuming hart %d", hartid); - if (riscv_set_current_hartid(target, hartid) != ERROR_OK) - return ERROR_FAIL; - if (!riscv_is_halted(target)) { - LOG_DEBUG(" hart %d requested resume, but was already resumed", hartid); - return ERROR_OK; - } - - r->on_resume(target); - return r->resume_current_hart(target); -} - int riscv_step_rtos_hart(struct target *target) { RISCV_INFO(r); @@ -2190,9 +2236,9 @@ int riscv_count_harts(struct target *target) if (target == NULL) return 1; RISCV_INFO(r); - if (r == NULL) + if (r == NULL || r->hart_count == NULL) return 1; - return r->hart_count; + return r->hart_count(target); } bool riscv_has_register(struct target *target, int hartid, int regid) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 59414fc..ade1bf0 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -46,9 +46,6 @@ typedef struct { struct command_context *cmd_ctx; void *version_specific; - /* The number of harts on this system. */ - int hart_count; - /* The hart that the RTOS thinks is currently being debugged. */ int rtos_hartid; @@ -100,6 +97,9 @@ typedef struct { * delays, causing them to be relearned. Used for testing. */ int reset_delays_wait; + /* This target has been prepped and is ready to step/resume. */ + bool prepped; + /* Helper functions that target the various RISC-V debug spec * implementations. */ int (*get_register)(struct target *target, @@ -109,10 +109,15 @@ typedef struct { int (*select_current_hart)(struct target *); bool (*is_halted)(struct target *target); int (*halt_current_hart)(struct target *); - int (*resume_current_hart)(struct target *target); + /* Resume this target, as well as every other prepped target that can be + * resumed near-simultaneously. Clear the prepped flag on any target that + * was resumed. */ + int (*resume_go)(struct target *target); int (*step_current_hart)(struct target *target); int (*on_halt)(struct target *target); - int (*on_resume)(struct target *target); + /* Get this target as ready as possible to resume, without actually + * resuming. */ + int (*resume_prep)(struct target *target); int (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); int (*write_debug_buffer)(struct target *target, unsigned index, @@ -134,6 +139,9 @@ typedef struct { uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); int (*test_compliance)(struct target *target); + + /* How many harts are attached to the DM that this target is attached to? */ + int (*hart_count)(struct target *target); } riscv_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ @@ -163,7 +171,7 @@ int riscv_openocd_poll(struct target *target); int riscv_openocd_halt(struct target *target); -int riscv_openocd_resume( +int riscv_resume( struct target *target, int current, target_addr_t address, @@ -191,8 +199,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r); * the system. */ int riscv_halt_all_harts(struct target *target); int riscv_halt_one_hart(struct target *target, int hartid); -int riscv_resume_all_harts(struct target *target); -int riscv_resume_one_hart(struct target *target, int hartid); /* Steps the hart that's currently selected in the RTOS, or if there is no RTOS * then the only hart. */ |