diff options
-rw-r--r-- | doc/openocd.texi | 5 | ||||
-rw-r--r-- | src/target/riscv/batch.c | 11 | ||||
-rw-r--r-- | src/target/riscv/batch.h | 26 | ||||
-rw-r--r-- | src/target/riscv/riscv-011.c | 10 | ||||
-rw-r--r-- | src/target/riscv/riscv-013.c | 539 | ||||
-rw-r--r-- | src/target/riscv/riscv.c | 24 | ||||
-rw-r--r-- | src/target/riscv/riscv.h | 16 | ||||
-rw-r--r-- | src/target/riscv/riscv_reg.c | 8 |
8 files changed, 193 insertions, 446 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi index a0c8ebb..5bd4e89 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11290,11 +11290,6 @@ Set the wall-clock timeout (in seconds) for individual commands. The default should work fine for all but the slowest targets (eg. simulators). @end deffn -@deffn {Command} {riscv set_reset_timeout_sec} [seconds] -Set the maximum time to wait for a hart to come out of reset after reset is -deasserted. -@end deffn - @deffn {Command} {riscv set_mem_access} method1 [method2] [method3] Specify which RISC-V memory access method(s) shall be used, and in which order of priority. At least one method must be specified. diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index bb1070a..afea316 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -190,8 +190,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, for (size_t i = start_idx; i < batch->used_scans; ++i) { const int delay = get_delay(batch, i, delays); - riscv_log_dmi_scan(batch->target, delay, batch->fields + i, - /*discard_in*/ false); + riscv_log_dmi_scan(batch->target, delay, batch->fields + i); } batch->was_run = true; @@ -199,14 +198,14 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, return ERROR_OK; } -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_write(batch->target, (char *)field->out_value, address, data); + riscv_fill_dmi_write(batch->target, (char *)field->out_value, address, data); if (read_back) { field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); riscv_fill_dm_nop(batch->target, (char *)field->in_value); @@ -218,7 +217,7 @@ void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint3 batch->used_scans++; } -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address, enum riscv_scan_delay_class delay_class) { assert(batch->used_scans < batch->allocated_scans); @@ -226,7 +225,7 @@ size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_read(batch->target, (char *)field->out_value, address); + riscv_fill_dmi_read(batch->target, (char *)field->out_value, address); riscv_fill_dm_nop(batch->target, (char *)field->in_value); batch->delay_classes[batch->used_scans] = delay_class; batch->last_scan = RISCV_SCAN_TYPE_READ; diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 1a39939..660a63f 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -190,14 +190,32 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, size_t riscv_batch_finished_scans(const struct riscv_batch *batch); /* Adds a DM register write to this batch. */ -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class); +static inline void +riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, + bool read_back, enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_write(batch, + riscv_get_dmi_address(batch->target, address), data, + read_back, delay_type); +} + /* DM register reads must be handled in two parts: the first one schedules a read and * provides a key, the second one actually obtains the result of the read - * status (op) and the actual data. */ -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address, enum riscv_scan_delay_class delay_class); + +static inline size_t +riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, + enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_read(batch, + riscv_get_dmi_address(batch->target, address), delay_type); +} + unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key); uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key); @@ -213,7 +231,7 @@ bool riscv_batch_was_batch_busy(const struct riscv_batch *batch); /* TODO: The function is defined in `riscv-013.c`. This is done to reduce the * diff of the commit. The intention is to move the function definition to * a separate module (e.g. `riscv013-jtag-dtm.c/h`) in another commit. */ -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, - bool discard_in); +void riscv_log_dmi_scan(const struct target *target, int idle, + const struct scan_field *field); #endif /* OPENOCD_TARGET_RISCV_BATCH_H */ diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index cd30a52..0715de5 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -741,7 +741,7 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first) if (!bits.interrupt) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out waiting for debug int to clear." "Increase timeout with riscv set_command_timeout_sec."); return ERROR_FAIL; @@ -1025,7 +1025,7 @@ static int wait_for_state(struct target *target, enum target_state state) return result; if (target->state == state) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out waiting for state %d. " "Increase timeout with riscv set_command_timeout_sec.", state); return ERROR_FAIL; @@ -1186,7 +1186,7 @@ static int full_step(struct target *target, bool announce) return result; if (target->state != TARGET_DEBUG_RUNNING) break; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out waiting for step to complete." "Increase timeout with riscv set_command_timeout_sec"); return ERROR_FAIL; @@ -2344,10 +2344,10 @@ static int wait_for_authbusy(struct target *target) uint32_t dminfo = dbus_read(target, DMINFO); if (!get_field(dminfo, DMINFO_AUTHBUSY)) break; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, + riscv_get_command_timeout_sec(), dminfo); return ERROR_FAIL; } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 07b6da0..ae36a06 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -56,10 +56,7 @@ static int riscv013_invalidate_cached_progbuf(struct target *target); static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr); static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a); -static void riscv013_fill_dmi_nop(struct target *target, char *buf); static int riscv013_get_dmi_scan_length(struct target *target); -static void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -static void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a); static void riscv013_fill_dm_nop(struct target *target, char *buf); static unsigned int register_size(struct target *target, enum gdb_regno number); static int register_read_direct(struct target *target, riscv_reg_t *value, @@ -376,7 +373,9 @@ static unsigned int decode_dmi(const struct target *target, char *text, uint32_t return 0; } -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, bool discard_in) +/* TODO: Move this function to "batch.c" and make it static. */ +void riscv_log_dmi_scan(const struct target *target, int idle, + const struct scan_field *field) { static const char * const op_string[] = {"-", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; @@ -400,7 +399,7 @@ void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address, idle); - if (!discard_in && in_op == DTM_DMI_OP_SUCCESS) { + if (in_op == DTM_DMI_OP_SUCCESS) { char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1]; decode_dmi(target, in_decoded, in_address, in_data); /* FIXME: The current code assumes that the hardware @@ -506,220 +505,6 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe "resetting learned delays (reset_delays_wait counter expired)"); reset_learned_delays(target); } -/** - * exec: If this is set, assume the scan results in an execution, so more - * run-test/idle cycles may be required. - */ -static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, - uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, - bool exec) -{ - riscv013_info_t *info = get_info(target); - unsigned num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH; - size_t num_bytes = (num_bits + 7) / 8; - uint8_t in[num_bytes]; - uint8_t out[num_bytes]; - struct scan_field field = { - .num_bits = num_bits, - .out_value = out, - .in_value = in - }; - riscv_bscan_tunneled_scan_context_t bscan_ctxt; - - decrement_reset_delays_counter(target, 1); - - memset(in, 0, num_bytes); - memset(out, 0, num_bytes); - - if (info->abits == 0) { - LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0."); - return DMI_STATUS_FAILED; - } - - buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); - buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); - buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); - - /* I wanted to place this code in a different function, but the way JTAG command - queueing works in the jtag handling functions, the scan fields either have to be - heap allocated, global/static, or else they need to stay on the stack until - the jtag_execute_queue() call. Heap or static fields in this case doesn't seem - the best fit. Declaring stack based field values in a subsidiary function call wouldn't - work. */ - if (bscan_tunnel_ir_width != 0) { - riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); - } else { - /* Assume dbus is already selected. */ - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - } - - int idle_count = exec - ? riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_ABSTRACT_COMMAND) - : riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE); - - if (idle_count) - jtag_add_runtest(idle_count, TAP_IDLE); - - int retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("dmi_scan failed jtag scan"); - if (data_in) - *data_in = ~0; - return DMI_STATUS_FAILED; - } - - if (bscan_tunnel_ir_width != 0) { - /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ - buffer_shr(in, num_bytes, 1); - } - - if (data_in) - *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); - - if (address_in) - *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - riscv_log_dmi_scan(target, idle_count, &field, /*discard_in*/ !data_in); - return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); -} - -/** - * @param target - * @param data_in The data we received from the target. - * @param dmi_busy_encountered - * If non-NULL, will be updated to reflect whether DMI busy was - * encountered while executing this operation or not. - * @param op The operation to perform (read/write/nop). - * @param address The address argument to that operation. - * @param data_out The data to send to the target. - * @param timeout_sec - * @param exec When true, this scan will execute something, so extra RTI - * cycles may be added. - * @param ensure_success - * Scan a nop after the requested operation, ensuring the - * DMI operation succeeded. - */ -static int dmi_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - select_dmi(target); - - dmi_status_t status; - - if (dmi_busy_encountered) - *dmi_busy_encountered = false; - - const char *op_name; - switch (op) { - case DMI_OP_NOP: - op_name = "nop"; - break; - case DMI_OP_READ: - op_name = "read"; - break; - case DMI_OP_WRITE: - op_name = "write"; - break; - default: - LOG_ERROR("Invalid DMI operation: %d", op); - return ERROR_FAIL; - } - - keep_alive(); - - time_t start = time(NULL); - /* This first loop performs the request. Note that if for some reason this - * stays busy, it is actually due to the previous access. */ - while (1) { - status = dmi_scan(target, NULL, NULL, op, address, data_out, - exec); - if (status == DMI_STATUS_BUSY) { - int result = increase_dmi_busy_delay(target); - if (result != ERROR_OK) - return result; - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - break; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - - if (status != DMI_STATUS_SUCCESS) { - LOG_TARGET_ERROR(target, "Failed DMI %s at 0x%x; status=%d", op_name, address, status); - return ERROR_FAIL; - } - - if (ensure_success) { - /* This second loop ensures the request succeeded, and gets back data. - * Note that NOP can result in a 'busy' result as well, but that would be - * noticed on the next DMI access we do. */ - while (1) { - status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0, - false); - if (status == DMI_STATUS_BUSY) { - int result = increase_dmi_busy_delay(target); - if (result != ERROR_OK) - return result; - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - if (data_in) { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; value=0x%x, status=%d", - op_name, address, *data_in, status); - } else { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address, - status); - } - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - return ERROR_FAIL; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - } - - return ERROR_OK; -} - -static int dmi_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) -{ - int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op, - address, data_out, riscv_command_timeout_sec, exec, ensure_success); - if (result == ERROR_TIMEOUT_REACHED) { - LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is " - "either really slow or broken. You could increase the " - "timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec); - return ERROR_FAIL; - } - return result; -} - -static int dmi_read(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); -} - -static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); -} - -static int dmi_write(struct target *target, uint32_t address, uint32_t value) -{ - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); -} static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address) { @@ -731,34 +516,22 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a return address + base; } -static int dm_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, timeout_sec, exec, ensure_success); -} +static int batch_run_timeout(struct target *target, struct riscv_batch *batch); -static int dm_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, exec, ensure_success); + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_read(batch, address, RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; } static int dm_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_read(target, value, address + dm->base); + return dmi_read(target, value, riscv013_get_dmi_address(target, address)); } static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address) @@ -766,16 +539,29 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dm_read(batch, address, RISCV_DELAY_ABSTRACT_COMMAND); dm->abstract_cmd_maybe_busy = true; - return dmi_read_exec(target, value, address + dm->base); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; +} + +static int dmi_write(struct target *target, uint32_t address, uint32_t value) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_write(batch, address, value, /*read_back*/ true, + RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int dm_write(struct target *target, uint32_t address, uint32_t value) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_write(target, address + dm->base, value); + return dmi_write(target, riscv013_get_dmi_address(target, address), value); } static bool check_dbgbase_exists(struct target *target) @@ -805,11 +591,10 @@ static bool check_dbgbase_exists(struct target *target) return false; } -static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, - bool authenticated, unsigned timeout_sec) +static int dmstatus_read(struct target *target, uint32_t *dmstatus, + bool authenticated) { - int result = dm_op_timeout(target, dmstatus, NULL, DMI_OP_READ, - DM_DMSTATUS, 0, timeout_sec, false, true); + int result = dm_read(target, dmstatus, DM_DMSTATUS); if (result != ERROR_OK) return result; int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION); @@ -827,19 +612,6 @@ static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, return ERROR_OK; } -static int dmstatus_read(struct target *target, uint32_t *dmstatus, - bool authenticated) -{ - int result = dmstatus_read_timeout(target, dmstatus, authenticated, - riscv_command_timeout_sec); - if (result == ERROR_TIMEOUT_REACHED) - LOG_TARGET_ERROR(target, "DMSTATUS read didn't complete in %d seconds. The target is " - "either really slow or broken. You could increase the " - "timeout with `riscv set_command_timeout_sec`.", - riscv_command_timeout_sec); - return result; -} - static int increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -890,12 +662,12 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) dm->abstract_cmd_maybe_busy = false; return ERROR_OK; } - } while ((time(NULL) - start) < riscv_command_timeout_sec); + } while ((time(NULL) - start) < riscv_get_command_timeout_sec()); LOG_TARGET_ERROR(target, "Timed out after %ds waiting for busy to go low (abstractcs=0x%" PRIx32 "). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, + riscv_get_command_timeout_sec(), *abstractcs); if (!dm->abstract_cmd_maybe_busy) @@ -955,8 +727,6 @@ clear_cmderr: return res; } -static int batch_run_timeout(struct target *target, struct riscv_batch *batch); - static int execute_abstract_command(struct target *target, uint32_t command, uint32_t *cmderr) { @@ -1898,10 +1668,10 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) *dmstatus = value; if (!get_field(value, DM_DMSTATUS_AUTHBUSY)) break; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, + riscv_get_command_timeout_sec(), value); return ERROR_FAIL; } @@ -2091,11 +1861,10 @@ static int reset_dm(struct target *target) if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_reset_timeout_sec) { - /* TODO: Introduce a separate timeout for this. */ + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "DM didn't acknowledge reset in %d s. " - "Increase the timeout with 'riscv set_reset_timeout_sec'.", - riscv_reset_timeout_sec); + "Increase the timeout with 'riscv set_command_timeout_sec'.", + riscv_get_command_timeout_sec()); return ERROR_TIMEOUT_REACHED; } } while (get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)); @@ -2114,11 +1883,10 @@ static int reset_dm(struct target *target) if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_reset_timeout_sec) { - /* TODO: Introduce a separate timeout for this. */ + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Debug Module did not become active in %d s. " - "Increase the timeout with 'riscv set_reset_timeout_sec'.", - riscv_reset_timeout_sec); + "Increase the timeout with 'riscv set_command_timeout_sec'.", + riscv_get_command_timeout_sec()); return ERROR_TIMEOUT_REACHED; } } while (!get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)); @@ -2743,21 +2511,42 @@ static uint32_t sb_sbaccess(unsigned int size_bytes) return 0; } -static int sb_write_address(struct target *target, target_addr_t address, - bool ensure_success) +static unsigned int get_sbaadress_reg_count(const struct target *target) { RISCV013_INFO(info); - unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + const unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + return DIV_ROUND_UP(sbasize, 32); +} + +static void batch_fill_sb_write_address(const struct target *target, + struct riscv_batch *batch, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ /* There currently is no support for >64-bit addresses in OpenOCD. */ - if (sbasize > 96) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); - if (sbasize > 64) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); - if (sbasize > 32) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, - (uint32_t)(address >> 32), false, false); - return dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, - (uint32_t)address, false, ensure_success); + assert(sizeof(target_addr_t) == sizeof(uint64_t)); + const uint32_t addresses[] = {DM_SBADDRESS0, DM_SBADDRESS1, DM_SBADDRESS2, DM_SBADDRESS3}; + const uint32_t values[] = {(uint32_t)address, (uint32_t)(address >> 32), 0, 0}; + const unsigned int reg_count = get_sbaadress_reg_count(target); + assert(reg_count > 0); + assert(reg_count <= ARRAY_SIZE(addresses)); + assert(ARRAY_SIZE(addresses) == ARRAY_SIZE(values)); + + for (unsigned int i = reg_count - 1; i > 0; --i) + riscv_batch_add_dm_write(batch, addresses[i], values[i], /* read back */ true, + RISCV_DELAY_BASE); + riscv_batch_add_dm_write(batch, addresses[0], values[0], /* read back */ true, + sbaddr0_delay); +} + +static int sb_write_address(struct target *target, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, + get_sbaadress_reg_count(target)); + batch_fill_sb_write_address(target, batch, address, sbaddr0_delay); + const int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int batch_run(struct target *target, struct riscv_batch *batch) @@ -2769,12 +2558,16 @@ static int batch_run(struct target *target, struct riscv_batch *batch) const int result = riscv_batch_run_from(batch, 0, &info->learned_delays, /*resets_delays*/ r->reset_delays_wait >= 0, r->reset_delays_wait); + if (result != ERROR_OK) + return result; /* TODO: To use `riscv_batch_finished_scans()` here, it is needed for * all scans to not discard input, meaning * "riscv_batch_add_dm_write(..., false)" should not be used. */ const size_t finished_scans = batch->used_scans; decrement_reset_delays_counter(target, finished_scans); - return result; + if (riscv_batch_was_batch_busy(batch)) + return increase_dmi_busy_delay(target); + return ERROR_OK; } /* It is expected that during creation of the batch @@ -2797,12 +2590,12 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) &info->learned_delays, /*resets_delays*/ r->reset_delays_wait >= 0, r->reset_delays_wait); + if (result != ERROR_OK) + return result; const size_t new_finished_scans = riscv_batch_finished_scans(batch); assert(new_finished_scans >= finished_scans); decrement_reset_delays_counter(target, new_finished_scans - finished_scans); finished_scans = new_finished_scans; - if (result != ERROR_OK) - return result; if (!riscv_batch_was_batch_busy(batch)) { assert(finished_scans == batch->used_scans); return ERROR_OK; @@ -2810,7 +2603,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) result = increase_dmi_busy_delay(target); if (result != ERROR_OK) return result; - } while (time(NULL) - start < riscv_command_timeout_sec); + } while (time(NULL) - start < riscv_get_command_timeout_sec()); assert(result == ERROR_OK); assert(riscv_batch_was_batch_busy(batch)); @@ -2825,7 +2618,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. " "The target is either really slow or broken. You could increase " "the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec); + riscv_get_command_timeout_sec()); return ERROR_TIMEOUT_REACHED; } @@ -3108,8 +2901,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->write_progbuf = &riscv013_write_progbuf; generic_info->execute_progbuf = &riscv013_execute_progbuf; generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf; - generic_info->fill_dm_write = &riscv013_fill_dm_write; - generic_info->fill_dm_read = &riscv013_fill_dm_read; + generic_info->fill_dmi_write = &riscv013_fill_dmi_write; + generic_info->fill_dmi_read = &riscv013_fill_dmi_read; generic_info->fill_dm_nop = &riscv013_fill_dm_nop; generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length; generic_info->authdata_read = &riscv013_authdata_read; @@ -3225,21 +3018,15 @@ static int deassert_reset(struct target *target) time_t start = time(NULL); LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset."); do { - result = dmstatus_read_timeout(target, &dmstatus, true, - riscv_reset_timeout_sec); - if (result == ERROR_TIMEOUT_REACHED) - LOG_TARGET_ERROR(target, "Hart didn't complete a DMI read coming " - "out of reset in %ds; Increase the timeout with riscv " - "set_reset_timeout_sec.", - riscv_reset_timeout_sec); + result = dmstatus_read(target, &dmstatus, true); if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_reset_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; " "dmstatus=0x%x (allunavail=%s, allhavereset=%s); " - "Increase the timeout with riscv set_reset_timeout_sec.", - riscv_reset_timeout_sec, dmstatus, + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_get_command_timeout_sec(), dmstatus, get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) ? "true" : "false", get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false"); return ERROR_TIMEOUT_REACHED; @@ -3425,10 +3212,10 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) return ERROR_FAIL; if (!get_field(*sbcs, DM_SBCS_SBBUSY)) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, *sbcs); + riscv_get_command_timeout_sec(), *sbcs); return ERROR_FAIL; } } @@ -3570,6 +3357,9 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t next_address = address; target_addr_t end_address = address + (increment ? count : 1) * size; + /* TODO: Reading all the elements in a single batch will boost the + * performance. + */ while (next_address < end_address) { uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1); sbcs_write |= sb_sbaccess(size); @@ -3581,96 +3371,51 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; /* This address write will trigger the first read. */ - if (sb_write_address(target, next_address, true) != ERROR_OK) + if (sb_write_address(target, next_address, RISCV_DELAY_SYSBUS_READ) != ERROR_OK) return ERROR_FAIL; - unsigned int bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays, - RISCV_DELAY_SYSBUS_READ); - if (bus_master_read_delay) { - LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", - bus_master_read_delay); - jtag_add_runtest(bus_master_read_delay, TAP_IDLE); - if (jtag_execute_queue() != ERROR_OK) { - LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); - return ERROR_FAIL; - } - } - /* First read has been started. Optimistically assume that it has * completed. */ static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3}; + /* TODO: The only purpose of "sbvalue" is to be passed to + * "log_memory_access()". If "log_memory_access()" were to + * accept "uint8_t *" instead of "uint32_t *", "sbvalue" would + * be unnecessary. + */ uint32_t sbvalue[4] = {0}; assert(size <= 16); - target_addr_t next_read = address - 1; - uint32_t buffer_offset = 0; - int next_read_j = 0; for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { - for (int j = (size - 1) / 4; j >= 0; j--) { - unsigned attempt = 0; - while (1) { - if (attempt++ > 100) { - LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" - " just past " TARGET_ADDR_FMT, next_read); - return ERROR_FAIL; - } - keep_alive(); - dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j], - DMI_OP_READ, sbdata[j] + dm->base, 0, false); - /* By reading from sbdata0, we have just initiated another system bus read. - * If necessary add a delay so the read can finish. */ - bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays, - RISCV_DELAY_SYSBUS_READ); - if (j == 0 && bus_master_read_delay) { - LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", - bus_master_read_delay); - jtag_add_runtest(bus_master_read_delay, TAP_IDLE); - if (jtag_execute_queue() != ERROR_OK) { - LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); - return ERROR_FAIL; - } - } + const uint32_t size_in_words = DIV_ROUND_UP(size, 4); + struct riscv_batch *batch = riscv_batch_alloc(target, size_in_words); + /* Read of sbdata0 must be performed as last because it + * starts the new bus data transfer + * (in case "sbcs.sbreadondata" was set above). + * We don't want to start the next bus read before we + * fetch all the data from the last bus read. */ + for (uint32_t j = size_in_words - 1; j > 0; --j) + riscv_batch_add_dm_read(batch, sbdata[j], RISCV_DELAY_BASE); + riscv_batch_add_dm_read(batch, sbdata[0], RISCV_DELAY_SYSBUS_READ); + + int res = batch_run_timeout(target, batch); + if (res != ERROR_OK) { + riscv_batch_free(batch); + return res; + } - if (status == DMI_STATUS_BUSY) - increase_dmi_busy_delay(target); - else if (status == DMI_STATUS_SUCCESS) - break; - else - return ERROR_FAIL; - } - if (next_read != address - 1) { - buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[next_read_j]); - if (next_read_j == 0) { - log_memory_access(next_read, sbvalue, size, true); - memset(sbvalue, 0, size); - } - } - next_read_j = j; - next_read = address + i * increment + next_read_j * 4; - buffer_offset = i * size + next_read_j * 4; + const size_t last_key = batch->read_keys_used - 1; + for (size_t k = 0; k <= last_key; ++k) { + sbvalue[k] = riscv_batch_get_dmi_read_data(batch, + last_key - k); + buf_set_u32(buffer + i * size + k * 4, 0, 8 * size, sbvalue[k]); } + riscv_batch_free(batch); + const target_addr_t read_addr = address + i * increment; + log_memory_access(read_addr, sbvalue, size, true); } uint32_t sbcs_read = 0; if (count > 1) { - unsigned attempt = 0; - while (1) { - if (attempt++ > 100) { - LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" - " just past " TARGET_ADDR_FMT, next_read); - return ERROR_FAIL; - } - dmi_status_t status = dmi_scan(target, NULL, &sbvalue[0], DMI_OP_NOP, 0, 0, false); - if (status == DMI_STATUS_BUSY) - increase_dmi_busy_delay(target); - else if (status == DMI_STATUS_SUCCESS) - break; - else - return ERROR_FAIL; - } - buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[0]); - log_memory_access(next_read, sbvalue, size, true); - /* "Writes to sbcs while sbbusy is high result in undefined behavior. * A debugger must not write to sbcs until it reads sbbusy as 0." */ if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) @@ -4740,9 +4485,10 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t next_address = address; target_addr_t end_address = address + count * size; - int result; + int result = sb_write_address(target, next_address, RISCV_DELAY_BASE); + if (result != ERROR_OK) + return result; - sb_write_address(target, next_address, true); while (next_address < end_address) { LOG_TARGET_DEBUG(target, "Transferring burst starting at address 0x%" TARGET_PRIxADDR, next_address); @@ -5593,7 +5339,7 @@ static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a) buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -static void riscv013_fill_dmi_nop(struct target *target, char *buf) +static void riscv013_fill_dm_nop(struct target *target, char *buf) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); @@ -5607,27 +5353,6 @@ static int riscv013_get_dmi_scan_length(struct target *target) return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } -void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_write(target, buf, a + dm->base, d); -} - -void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_read(target, buf, a + dm->base); -} - -void riscv013_fill_dm_nop(struct target *target, char *buf) -{ - riscv013_fill_dmi_nop(target, buf); -} - static int maybe_execute_fence_i(struct target *target) { if (has_sufficient_progbuf(target, 2)) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 9c4796d..267d20d 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -140,10 +140,15 @@ struct tdata1_cache { }; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ -int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; +static int riscv_command_timeout_sec_value = DEFAULT_COMMAND_TIMEOUT_SEC; -/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ -int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; +/* DEPRECATED Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ +static int riscv_reset_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; + +int riscv_get_command_timeout_sec(void) +{ + return MAX(riscv_command_timeout_sec_value, riscv_reset_timeout_sec); +} static bool riscv_enable_virt2phys = true; @@ -3853,13 +3858,14 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) return ERROR_FAIL; } - riscv_command_timeout_sec = timeout; + riscv_command_timeout_sec_value = timeout; return ERROR_OK; } COMMAND_HANDLER(riscv_set_reset_timeout_sec) { + LOG_WARNING("The command 'riscv set_reset_timeout_sec' is deprecated! Please, use 'riscv set_command_timeout_sec'."); if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter."); return ERROR_COMMAND_SYNTAX_ERROR; @@ -5066,7 +5072,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, .usage = "[sec]", - .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" + .help = "DEPRECATED. Use 'riscv set_command_timeout_sec' instead." }, { .name = "set_mem_access", @@ -5581,16 +5587,16 @@ int riscv_execute_progbuf(struct target *target, uint32_t *cmderr) return r->execute_progbuf(target, cmderr); } -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) +void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) { RISCV_INFO(r); - r->fill_dm_write(target, buf, a, d); + r->fill_dmi_write(target, buf, a, d); } -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a) +void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a) { RISCV_INFO(r); - r->fill_dm_read(target, buf, a); + r->fill_dmi_read(target, buf, a); } void riscv_fill_dm_nop(struct target *target, char *buf) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index c13af8e..a25aac8 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -22,8 +22,7 @@ struct riscv_program; #define RISCV_MAX_HWBPS 16 #define RISCV_MAX_DMS 100 -#define DEFAULT_COMMAND_TIMEOUT_SEC 2 -#define DEFAULT_RESET_TIMEOUT_SEC 30 +#define DEFAULT_COMMAND_TIMEOUT_SEC 5 #define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE) #define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN) @@ -227,8 +226,8 @@ struct riscv_info { int (*execute_progbuf)(struct target *target, uint32_t *cmderr); int (*invalidate_cached_progbuf)(struct target *target); int (*get_dmi_scan_length)(struct target *target); - void (*fill_dm_write)(struct target *target, char *buf, uint64_t a, uint32_t d); - void (*fill_dm_read)(struct target *target, char *buf, uint64_t a); + void (*fill_dmi_write)(struct target *target, char *buf, uint64_t a, uint32_t d); + void (*fill_dmi_read)(struct target *target, char *buf, uint64_t a); void (*fill_dm_nop)(struct target *target, char *buf); int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); @@ -340,10 +339,7 @@ typedef struct { } virt2phys_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ -extern int riscv_command_timeout_sec; - -/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ -extern int riscv_reset_timeout_sec; +int riscv_get_command_timeout_sec(void); extern bool riscv_enable_virtual; @@ -412,8 +408,8 @@ int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn); int riscv_execute_progbuf(struct target *target, uint32_t *cmderr); void riscv_fill_dm_nop(struct target *target, char *buf); -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a); +void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); +void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a); int riscv_get_dmi_scan_length(struct target *target); uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address); diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index f8e5dfe..6cf67dd 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -397,6 +397,14 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_FRM: case CSR_FCSR: return riscv_supports_extension(target, 'F'); + case CSR_VSTART: + case CSR_VXSAT: + case CSR_VXRM: + case CSR_VL: + case CSR_VCSR: + case CSR_VTYPE: + case CSR_VLENB: + return vlenb_exists(target); case CSR_SCOUNTEREN: case CSR_SSTATUS: case CSR_STVEC: |