From 2c4118ecea85cbf972e420ab29b5d299ad58f13c Mon Sep 17 00:00:00 2001 From: Parshintsev Anatoly Date: Thu, 28 Sep 2023 10:14:07 +0300 Subject: [PATCH] do not assume DTM version unless dtmcontrol is read successfully Change-Id: I5f2003b7ac5ce87af6ca9a4fcb46140682a8cfdf Signed-off-by: Parshintsev Anatoly --- src/target/riscv/riscv-011.c | 19 +++++---- src/target/riscv/riscv-013.c | 26 +++++++------ src/target/riscv/riscv.c | 75 ++++++++++++++++++++++++++++-------- src/target/riscv/riscv.h | 6 ++- 4 files changed, 88 insertions(+), 38 deletions(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index fb94983529..dd7676ee78 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -273,7 +273,7 @@ static uint16_t dram_address(unsigned int index) return 0x40 + index - 0x10; } -static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { struct scan_field field; uint8_t in_value[4]; @@ -300,7 +300,9 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } static uint32_t idcode_scan(struct target *target) @@ -338,7 +340,7 @@ static void increase_dbus_busy_delay(struct target *target) info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); - dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET); + dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET, NULL /* discard value */); } static void increase_interrupt_high_delay(struct target *target) @@ -1459,16 +1461,17 @@ static int step(struct target *target, int current, target_addr_t address, static int examine(struct target *target) { /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + uint32_t dtmcontrol; + if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + LOG_ERROR("Could not scan dtmcontrol. Check JTAG connectivity/board power."); + return ERROR_FAIL; + } - uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); LOG_DEBUG(" addrbits=%d", get_field(dtmcontrol, DTMCONTROL_ADDRBITS)); LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTMCONTROL_VERSION)); LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTMCONTROL_IDLE)); - if (dtmcontrol == 0) { - LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); - return ERROR_FAIL; - } + if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) { LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", get_field(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 7d3d95054e..01e1c6fe01 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -411,14 +411,14 @@ static void select_dmi(struct target *target) jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); } -static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out); + return dtmcontrol_scan_via_bscan(target, out, in_ptr); buf_set_u32(out_value, 0, 32, out); @@ -441,7 +441,9 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } static void increase_dmi_busy_delay(struct target *target) @@ -452,7 +454,7 @@ static void increase_dmi_busy_delay(struct target *target) info->dtmcs_idle, info->dmi_busy_delay, info->ac_busy_delay); - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); } /** @@ -597,7 +599,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, } else if (status == DMI_STATUS_SUCCESS) { break; } else { - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); break; } if (time(NULL) - start > timeout_sec) @@ -632,7 +634,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, "Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address, status); } - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); return ERROR_FAIL; } if (time(NULL) - start > timeout_sec) @@ -1845,17 +1847,19 @@ static int examine(struct target *target) /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ LOG_TARGET_DEBUG(target, "dbgbase=0x%x", target->dbgbase); - uint32_t dtmcontrol = dtmcontrol_scan(target, 0); + uint32_t dtmcontrol; + if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + LOG_TARGET_ERROR(target, "Could not scan dtmcontrol. Check JTAG connectivity/board power."); + return ERROR_FAIL; + } + LOG_TARGET_DEBUG(target, "dtmcontrol=0x%x", dtmcontrol); LOG_TARGET_DEBUG(target, " dmireset=%d", get_field(dtmcontrol, DTM_DTMCS_DMIRESET)); LOG_TARGET_DEBUG(target, " idle=%d", get_field(dtmcontrol, DTM_DTMCS_IDLE)); LOG_TARGET_DEBUG(target, " dmistat=%d", get_field(dtmcontrol, DTM_DTMCS_DMISTAT)); LOG_TARGET_DEBUG(target, " abits=%d", get_field(dtmcontrol, DTM_DTMCS_ABITS)); LOG_TARGET_DEBUG(target, " version=%d", get_field(dtmcontrol, DTM_DTMCS_VERSION)); - if (dtmcontrol == 0) { - LOG_TARGET_ERROR(target, "dtmcontrol is 0. Check JTAG connectivity/board power."); - return ERROR_FAIL; - } + if (get_field(dtmcontrol, DTM_DTMCS_VERSION) != 1) { LOG_TARGET_ERROR(target, "Unsupported DTM version %d. (dtmcontrol=0x%x)", get_field(dtmcontrol, DTM_DTMCS_VERSION), dtmcontrol); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a544cbdfd7..a207a44420 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -281,7 +281,7 @@ void select_dmi_via_bscan(struct target *target) bscan_tunnel_nested_tap_select_dmi, TAP_IDLE); } -uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out) +int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr) { /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */ uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width}; @@ -362,18 +362,19 @@ uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out) uint32_t in = buf_get_u32(in_value, 1, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } -static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out); - + return dtmcontrol_scan_via_bscan(target, out, in_ptr); buf_set_u32(out_value, 0, 32, out); @@ -389,14 +390,16 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) int retval = jtag_execute_queue(); if (retval != ERROR_OK) { - LOG_ERROR("failed jtag scan: %d", retval); + LOG_TARGET_ERROR(target, "dtmcontrol scan failed, error code = %d", retval); return retval; } uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } static struct target_type *get_target_type(struct target *target) @@ -408,11 +411,13 @@ static struct target_type *get_target_type(struct target *target) RISCV_INFO(info); switch (info->dtm_version) { - case 0: + case DTM_DTMCS_VERSION_0_11: return &riscv011_target; - case 1: + case DTM_DTMCS_VERSION_1_0: return &riscv013_target; default: + /* TODO: once we have proper support for non-examined targets + * we should have an assert here */ LOG_TARGET_ERROR(target, "Unsupported DTM version: %d", info->dtm_version); return NULL; @@ -479,6 +484,7 @@ static void riscv_free_registers(struct target *target) free(target->reg_cache->reg_list); } free(target->reg_cache); + target->reg_cache = NULL; } } @@ -488,6 +494,8 @@ static void riscv_deinit_target(struct target *target) struct riscv_info *info = target->arch_info; struct target_type *tt = get_target_type(target); + if (!tt) + LOG_TARGET_ERROR(target, "Could not identify target type."); if (riscv_flush_registers(target) != ERROR_OK) LOG_TARGET_ERROR(target, "Failed to flush registers. Ignoring this error."); @@ -1517,6 +1525,8 @@ static int oldriscv_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->step(target, current, address, handle_breakpoints); } @@ -1542,25 +1552,40 @@ static int riscv_examine(struct target *target) /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ RISCV_INFO(info); - uint32_t dtmcontrol = dtmcontrol_scan(target, 0); + uint32_t dtmcontrol; + if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + LOG_TARGET_ERROR(target, "Could not read dtmcontrol. Check JTAG connectivity/board power."); + return ERROR_FAIL; + } LOG_TARGET_DEBUG(target, "dtmcontrol=0x%x", dtmcontrol); info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); LOG_TARGET_DEBUG(target, "version=0x%x", info->dtm_version); + int examine_status = ERROR_FAIL; struct target_type *tt = get_target_type(target); if (!tt) - return ERROR_FAIL; + goto examine_fail; - int result = tt->init_target(info->cmd_ctx, target); - if (result != ERROR_OK) - return result; + examine_status = tt->init_target(info->cmd_ctx, target); + if (examine_status != ERROR_OK) + goto examine_fail; + + examine_status = tt->examine(target); + if (examine_status != ERROR_OK) + goto examine_fail; + + return ERROR_OK; - return tt->examine(target); +examine_fail: + info->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; + return examine_status; } static int oldriscv_poll(struct target *target) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->poll(target); } @@ -1694,6 +1719,8 @@ static int halt_go(struct target *target) int result; if (!r->get_hart_state) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; result = tt->halt(target); } else { result = riscv_halt_go_all_harts(target); @@ -1715,6 +1742,8 @@ int riscv_halt(struct target *target) if (!r->get_hart_state) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->halt(target); } @@ -1760,6 +1789,8 @@ static int riscv_assert_reset(struct target *target) { LOG_TARGET_DEBUG(target, "coreid: [%d]", target->coreid); struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; riscv_invalidate_register_cache(target); return tt->assert_reset(target); } @@ -1768,6 +1799,8 @@ static int riscv_deassert_reset(struct target *target) { LOG_TARGET_DEBUG(target, "coreid: [%d]", target->coreid); struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->deassert_reset(target); } @@ -1900,6 +1933,8 @@ static int resume_go(struct target *target, int current, int result; if (!r->get_hart_state) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; result = tt->resume(target, current, address, handle_breakpoints, debug_execution); } else { @@ -2400,6 +2435,8 @@ static int riscv_write_phys_memory(struct target *target, target_addr_t phys_add uint32_t size, uint32_t count, const uint8_t *buffer) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->write_memory(target, phys_address, size, count, buffer); } @@ -2416,6 +2453,8 @@ static int riscv_write_memory(struct target *target, target_addr_t address, address = physical_addr; struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->write_memory(target, address, size, count, buffer); } @@ -2493,6 +2532,8 @@ static int riscv_get_gdb_reg_list(struct target *target, static int riscv_arch_state(struct target *target) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->arch_state(target); } @@ -4230,7 +4271,7 @@ COMMAND_HANDLER(riscv_exec_progbuf) struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); - if (r->dtm_version != 1) { + if (r->dtm_version != DTM_DTMCS_VERSION_1_0) { LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is " "only supported on v0.13 or v1.0 targets."); return ERROR_FAIL; @@ -4628,7 +4669,7 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) r->common_magic = RISCV_COMMON_MAGIC; - r->dtm_version = 1; + r->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; r->version_specific = NULL; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 3cf6aac262..01e9932183 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -111,10 +111,12 @@ typedef struct { char *name; } range_list_t; +#define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1) + struct riscv_info { unsigned int common_magic; - unsigned dtm_version; + unsigned int dtm_version; struct command_context *cmd_ctx; void *version_specific; @@ -357,7 +359,7 @@ extern uint32_t bscan_tunneled_select_dmi_num_fields; typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t; extern int bscan_tunnel_ir_width; -uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out); +int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr); void select_dmi_via_bscan(struct target *target); /*** OpenOCD Interface */