diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 3b7c6cc02..2af2221d5 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -433,8 +433,8 @@ static void increase_dmi_busy_delay(struct target *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, uint16_t *address_in, - uint32_t *data_in, dmi_op_t op, uint16_t address_out, uint32_t data_out, +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); @@ -479,12 +479,12 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } -static uint32_t dmi_read(struct target *target, uint16_t address) +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { select_dmi(target); dmi_status_t status; - uint16_t address_in; + uint32_t address_in; unsigned i = 0; @@ -500,21 +500,20 @@ static uint32_t dmi_read(struct target *target, uint16_t address) break; } else { LOG_ERROR("failed read from 0x%x, status=%d", address, status); - break; + return ERROR_FAIL; } } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed read from 0x%x; status=%d", address, status); - return ~0; + return ERROR_FAIL; } /* This second loop ensures that we got the read * data back. Note that NOP can result in a 'busy' result as well, but * that would be noticed on the next DMI access we do. */ - uint32_t value; for (i = 0; i < 256; i++) { - status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0, + status = dmi_scan(target, &address_in, value, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); @@ -522,7 +521,7 @@ static uint32_t dmi_read(struct target *target, uint16_t address) break; } else { LOG_ERROR("failed read (NOP) at 0x%x, status=%d", address, status); - break; + return ERROR_FAIL; } } @@ -531,15 +530,15 @@ static uint32_t dmi_read(struct target *target, uint16_t address) LOG_ERROR("Failed read (NOP) from 0x%x; status=%d", address, status); } else { LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%x, status=%d", - address, value, status); + address, *value, status); } - return ~0; + return ERROR_FAIL; } - return value; + return ERROR_OK; } -static int dmi_write(struct target *target, uint16_t address, uint64_t value) +static int dmi_write(struct target *target, uint32_t address, uint32_t value) { select_dmi(target); dmi_status_t status = DMI_STATUS_BUSY; @@ -581,7 +580,7 @@ static int dmi_write(struct target *target, uint16_t address, uint64_t value) } } if (status != DMI_STATUS_SUCCESS) { - LOG_ERROR("failed to write (NOP) 0x%" PRIx64 " to 0x%x; status=%d", value, address, status); + LOG_ERROR("failed to write (NOP) 0x%x to 0x%x; status=%d", value, address, status); return ERROR_FAIL; } @@ -591,7 +590,8 @@ static int dmi_write(struct target *target, uint16_t address, uint64_t value) int dmstatus_read(struct target *target, uint32_t *dmstatus, bool authenticated) { - *dmstatus = dmi_read(target, DMI_DMSTATUS); + if (dmi_read(target, dmstatus, DMI_DMSTATUS) != ERROR_OK) + return ERROR_FAIL; if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Debugger is not authenticated to target Debug Module. " "(dmstatus=0x%x). Use `riscv authdata_read` and " @@ -632,7 +632,8 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) RISCV013_INFO(info); time_t start = time(NULL); while (1) { - *abstractcs = dmi_read(target, DMI_ABSTRACTCS); + if (dmi_read(target, abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) return ERROR_OK; @@ -674,7 +675,9 @@ static int execute_abstract_command(struct target *target, uint32_t command) wait_for_idle(target, &abstractcs); } - uint32_t cs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t cs; + if (dmi_read(target, &cs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR); if (info->cmderr != 0) { LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs); @@ -691,16 +694,19 @@ static riscv_reg_t read_abstract_arg(struct target *target, unsigned index, unsigned size_bits) { riscv_reg_t value = 0; + uint32_t v; unsigned offset = index * size_bits / 32; switch (size_bits) { default: LOG_ERROR("Unsupported size: %d", size_bits); return ~0; case 64: - value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32; + dmi_read(target, &v, DMI_DATA0 + offset + 1); + value |= ((uint64_t) v) << 32; /* falls through */ case 32: - value |= dmi_read(target, DMI_DATA0 + offset); + dmi_read(target, &v, DMI_DATA0 + offset); + value |= v; } return value; } @@ -871,7 +877,9 @@ static int examine_progbuf(struct target *target) return ERROR_OK; } - uint32_t written = dmi_read(target, DMI_PROGBUF0); + uint32_t written; + if (dmi_read(target, &written, DMI_PROGBUF0) != ERROR_OK) + return ERROR_FAIL; if (written == (uint32_t) info->progbuf_address) { LOG_INFO("progbuf is writable at 0x%" PRIx64, info->progbuf_address); @@ -961,16 +969,23 @@ static int scratch_find(struct target *target, static int scratch_read64(struct target *target, scratch_mem_t *scratch, uint64_t *value) { + uint32_t v; switch (scratch->memory_space) { case SPACE_DMI_DATA: - *value = dmi_read(target, DMI_DATA0 + scratch->debug_address); - *value |= ((uint64_t) dmi_read(target, DMI_DATA1 + - scratch->debug_address)) << 32; + if (dmi_read(target, &v, DMI_DATA0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DMI_DATA1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_PROGBUF: - *value = dmi_read(target, DMI_PROGBUF0 + scratch->debug_address); - *value |= ((uint64_t) dmi_read(target, DMI_PROGBUF1 + - scratch->debug_address)) << 32; + if (dmi_read(target, &v, DMI_PROGBUF0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DMI_PROGBUF1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_RAM: { @@ -1269,7 +1284,9 @@ static int examine(struct target *target) uint32_t max_hartsel_mask = ((1L<<10)-1) << DMI_DMCONTROL_HARTSEL_OFFSET; dmi_write(target, DMI_DMCONTROL, max_hartsel_mask | DMI_DMCONTROL_DMACTIVE); - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", @@ -1285,7 +1302,9 @@ static int examine(struct target *target) } LOG_DEBUG("hartsellen=%d", info->hartsellen); - uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); + uint32_t hartinfo; + if (dmi_read(target, &hartinfo, DMI_HARTINFO) != ERROR_OK) + return ERROR_FAIL; info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); @@ -1302,10 +1321,13 @@ static int examine(struct target *target) return ERROR_OK; } - info->sbcs = dmi_read(target, DMI_SBCS); + if (dmi_read(target, &info->sbcs, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; /* Check that abstract data registers are accessible. */ - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); @@ -1412,8 +1434,7 @@ int riscv013_authdata_read(struct target *target, uint32_t *value) if (wait_for_authbusy(target, NULL) != ERROR_OK) return ERROR_FAIL; - *value = dmi_read(target, DMI_AUTHDATA); - return ERROR_OK; + return dmi_read(target, value, DMI_AUTHDATA); } int riscv013_authdata_write(struct target *target, uint32_t value) @@ -1469,6 +1490,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; generic_info->authdata_read = &riscv013_authdata_read; generic_info->authdata_write = &riscv013_authdata_write; + generic_info->dmi_read = &dmi_read; + generic_info->dmi_write = &dmi_write; generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; @@ -1533,7 +1556,9 @@ static int assert_reset(struct target *target) dmi_write(target, DMI_DMCONTROL, control); /* Read back to check if hartreset is supported. */ - uint32_t rb = dmi_read(target, DMI_DMCONTROL); + uint32_t rb; + if (dmi_read(target, &rb, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) { /* Use ndmreset instead. That will reset the entire device, but * that's probably what OpenOCD wants anyway. */ @@ -1668,21 +1693,25 @@ static int read_memory_bus_word(struct target *target, target_addr_t address, { uint32_t value; if (size > 12) { - value = dmi_read(target, DMI_SBDATA3); + if (dmi_read(target, &value, DMI_SBDATA3) != ERROR_OK) + return ERROR_FAIL; write_to_buf(buffer + 12, value, 4); log_memory_access(address + 12, value, 4, true); } if (size > 8) { - value = dmi_read(target, DMI_SBDATA2); + if (dmi_read(target, &value, DMI_SBDATA2) != ERROR_OK) + return ERROR_FAIL; write_to_buf(buffer + 8, value, 4); log_memory_access(address + 8, value, 4, true); } if (size > 4) { - value = dmi_read(target, DMI_SBDATA1); + if (dmi_read(target, &value, DMI_SBDATA1) != ERROR_OK) + return ERROR_FAIL; write_to_buf(buffer + 4, value, 4); log_memory_access(address + 4, value, 4, true); } - value = dmi_read(target, DMI_SBDATA0); + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; write_to_buf(buffer, value, MIN(size, 4)); log_memory_access(address, value, MIN(size, 4), true); return ERROR_OK; @@ -1711,13 +1740,16 @@ static target_addr_t sb_read_address(struct target *target) RISCV013_INFO(info); unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); target_addr_t address = 0; + uint32_t v; if (sbasize > 32) { #if BUILD_TARGET64 - address |= dmi_read(target, DMI_SBADDRESS1); + dmi_read(target, &v, DMI_SBADDRESS1); + address |= v; address <<= 32; #endif } - address |= dmi_read(target, DMI_SBADDRESS0); + dmi_read(target, &v, DMI_SBADDRESS0); + address |= v; return address; } @@ -1746,7 +1778,8 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) { time_t start = time(NULL); while (1) { - *sbcs = dmi_read(target, DMI_SBCS); + if (dmi_read(target, sbcs, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; if (!get_field(*sbcs, DMI_SBCS_SBBUSY)) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { @@ -1924,9 +1957,12 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, /* Wait for the target to finish performing the last abstract command, * and update our copy of cmderr. */ - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - abstractcs = dmi_read(target, DMI_ABSTRACTCS); + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); unsigned cmderr = info->cmderr; @@ -1975,7 +2011,10 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, /* This is definitely a good version of the value that we * attempted to read when we discovered that the target was * busy. */ - dmi_data0 = dmi_read(target, DMI_DATA0); + if (dmi_read(target, &dmi_data0, DMI_DATA0) != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } /* Clobbers DMI_DATA0. */ result = register_read_direct(target, &next_read_addr, @@ -2035,7 +2074,9 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, if (count > 1) { /* Read the penultimate word. */ - uint64_t value = dmi_read(target, DMI_DATA0); + uint32_t value; + if (dmi_read(target, &value, DMI_DATA0) != ERROR_OK) + goto error; write_to_buf(buffer + receive_addr - address, value, size); log_memory_access(receive_addr, value, size, true); receive_addr += size; @@ -2292,9 +2333,12 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, * is this read to abstractcs that will cause the dmi_busy_delay * to be incremented if necessary. */ - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + goto error; while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - abstractcs = dmi_read(target, DMI_ABSTRACTCS); + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); switch (info->cmderr) { case CMDERR_NONE: @@ -2440,7 +2484,8 @@ static void riscv013_select_current_hart(struct target *target) { RISCV_INFO(r); - uint64_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + dmi_read(target, &dmcontrol, DMI_DMCONTROL); dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid); dmi_write(target, DMI_DMCONTROL, dmcontrol); } @@ -2453,7 +2498,9 @@ static int riscv013_halt_current_hart(struct target *target) LOG_ERROR("Hart %d is already halted!", r->current_hartid); /* Issue the halt command, and then wait for the current hart to halt. */ - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) @@ -2464,7 +2511,8 @@ static int riscv013_halt_current_hart(struct target *target) uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; - dmcontrol = dmi_read(target, DMI_DMCONTROL); + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; LOG_ERROR("unable to halt hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); @@ -2546,7 +2594,9 @@ int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_ins riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { - return dmi_read(target, DMI_PROGBUF0 + index); + uint32_t value; + dmi_read(target, &value, DMI_PROGBUF0 + index); + return value; } int riscv013_execute_debug_buffer(struct target *target) @@ -2638,7 +2688,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step return ERROR_FAIL; /* Issue the resume command, and then wait for the current hart to resume. */ - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); @@ -2659,7 +2711,8 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; - dmcontrol = dmi_read(target, DMI_DMCONTROL); + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; LOG_ERROR("unable to resume hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); LOG_ERROR(" dmstatus =0x%08x", dmstatus); @@ -2677,9 +2730,10 @@ void riscv013_clear_abstract_error(struct target *target) { /* Wait for busy to go away. */ time_t start = time(NULL); - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) { - abstractcs = dmi_read(target, DMI_ABSTRACTCS); + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("abstractcs.busy is not going low after %d seconds " diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 6902ec283..9f16a400a 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1361,6 +1361,61 @@ COMMAND_HANDLER(riscv_authdata_write) } } +COMMAND_HANDLER(riscv_dmi_read) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->dmi_read) { + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + if (r->dmi_read(target, &value, address) != ERROR_OK) + return ERROR_FAIL; + command_print(CMD_CTX, "0x%" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("dmi_read is not implemented for this target."); + return ERROR_FAIL; + } +} + + +COMMAND_HANDLER(riscv_dmi_write) +{ + if (CMD_ARGC != 2) { + LOG_ERROR("Command takes exactly 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (r->dmi_write) { + return r->dmi_write(target, address, value); + } else { + LOG_ERROR("dmi_write is not implemented for this target."); + return ERROR_FAIL; + } +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "set_command_timeout_sec", @@ -1406,6 +1461,20 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "riscv authdata_write value", .help = "Write the 32-bit value to authdata." }, + { + .name = "dmi_read", + .handler = riscv_dmi_read, + .mode = COMMAND_ANY, + .usage = "riscv dmi_read address", + .help = "Perform a 32-bit DMI read at address, returning the value." + }, + { + .name = "dmi_write", + .handler = riscv_dmi_write, + .mode = COMMAND_ANY, + .usage = "riscv dmi_write address value", + .help = "Perform a 32-bit DMI write of value at address." + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index a5c8789ac..626b71f83 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -113,6 +113,9 @@ typedef struct { int (*authdata_read)(struct target *target, uint32_t *value); int (*authdata_write)(struct target *target, uint32_t value); + + int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); + int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); } riscv_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/