diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 30b4d8d4f..301b67af8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -910,7 +910,6 @@ static int init_target(struct command_context *cmd_ctx, generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; generic_info->reset_current_hart = &riscv013_reset_current_hart; generic_info->test_compliance = &riscv013_test_compliance; - generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; @@ -1355,8 +1354,10 @@ static int read_memory(struct target *target, target_addr_t address, riscv_addr_t fin_addr = address + (count * size); riscv_addr_t prev_addr = ((riscv_addr_t) address) - size; bool first = true; - LOG_DEBUG("writing until final address 0x%" PRIx64, fin_addr); - while (count > 1 && (cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) { + bool this_is_last_read = false; + LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); + while (count > 1 && !this_is_last_read) { + cur_addr = riscv_read_debug_buffer_x(target, d_addr); LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR " (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr, prev_addr); @@ -1373,11 +1374,22 @@ static int read_memory(struct target *target, target_addr_t address, size_t reads = 0; size_t rereads = reads; for (riscv_addr_t i = start; i < count; ++i) { - size_t index = - riscv_batch_add_dmi_read( - batch, - riscv013_debug_buffer_register(target, r_data)); - assert(index == reads); + if (i == count - 1) { + // don't do actual read in this batch, + // we will do it later after we disable autoexec + // + // this is done to avoid reading more memory than requested + // which in some special cases(like reading stack located + // at the very top of RAM) may cause an exception + this_is_last_read = true; + } else { + size_t const index = + riscv_batch_add_dmi_read( + batch, + riscv013_debug_buffer_register(target, r_data)); + assert(index == reads); + } + reads++; if (riscv_batch_full(batch)) break; @@ -1385,13 +1397,54 @@ static int read_memory(struct target *target, target_addr_t address, riscv_batch_run(batch); + // Note that if the scan resulted in a Busy DMI response, it + // is this read to abstractcs that will cause the dmi_busy_delay + // to be incremented if necessary. The loop condition above + // catches the case where no writes went through at all. + + bool retry_batch_transaction = false; + uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) + abstractcs = dmi_read(target, DMI_ABSTRACTCS); + info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + switch (info->cmderr) { + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory write"); + break; + case CMDERR_BUSY: + LOG_DEBUG("memory write resulted in busy response"); + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + retry_batch_transaction = true; + riscv_batch_free(batch); + break; + default: + LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_set_autoexec(target, d_data, 0); + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + riscv013_clear_abstract_error(target); + riscv_batch_free(batch); + return ERROR_FAIL; + } + if (retry_batch_transaction) continue; + for (size_t i = start; i < start + reads; ++i) { riscv_addr_t offset = size*i; riscv_addr_t t_addr = address + offset; uint8_t *t_buffer = buffer + offset; - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); - value = get_field(dmi_out, DTM_DMI_DATA); + if (this_is_last_read && i == start + reads - 1) { + riscv013_set_autoexec(target, d_data, 0); + + // access debug buffer without executing a program - this address logic was taken from program.c + int const off = (r_data - riscv_debug_buffer_addr(program.target)) / sizeof(program.debug_buffer[0]); + value = riscv_read_debug_buffer(target, off); + } else { + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); + value = get_field(dmi_out, DTM_DMI_DATA); + } + rereads++; switch (size) { @@ -1415,35 +1468,7 @@ static int read_memory(struct target *target, target_addr_t address, LOG_DEBUG("M[0x%08lx] reads 0x%08lx", (long)t_addr, (long)value); } - riscv_batch_free(batch); - - // Note that if the scan resulted in a Busy DMI response, it - // is this read to abstractcs that will cause the dmi_busy_delay - // to be incremented if necessary. The loop condition above - // catches the case where no writes went through at all. - - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); - while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - abstractcs = dmi_read(target, DMI_ABSTRACTCS); - info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); - switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory write"); - break; - case CMDERR_BUSY: - LOG_DEBUG("memory write resulted in busy response"); - riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); - break; - default: - LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - riscv013_clear_abstract_error(target); - return ERROR_FAIL; - } } riscv013_set_autoexec(target, d_data, 0); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index fca20215a..68ae309cf 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1137,8 +1137,96 @@ int riscv_openocd_deassert_reset(struct target *target) return ERROR_OK; } -// Declared below -const struct command_registration riscv_command_handlers[]; +/* Command Handlers */ +COMMAND_HANDLER(riscv_set_command_timeout_sec) { + + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int timeout = atoi(CMD_ARGV[0]); + if (timeout <= 0){ + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + riscv_command_timeout_sec = timeout; + + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_reset_timeout_sec) { + + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int timeout = atoi(CMD_ARGV[0]); + if (timeout <= 0){ + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + riscv_reset_timeout_sec = timeout; + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_test_compliance) { + + struct target *target = get_current_target(CMD_CTX); + + RISCV_INFO(r); + + if (CMD_ARGC > 0) { + LOG_ERROR("Command does not take any parameters."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (r->test_compliance) { + return r->test_compliance(target); + } else { + LOG_ERROR("This target does not support this command (may implement an older version of the spec)."); + return ERROR_FAIL; + } + +} + + +static const struct command_registration riscv_exec_command_handlers[] = { + { + .name = "test_compliance", + .handler = riscv_test_compliance, + .mode = COMMAND_EXEC, + .usage = "riscv test_compliance", + .help = "Runs a basic compliance test suite against the RISC-V Debug Spec." + }, + { + .name = "set_command_timeout_sec", + .handler = riscv_set_command_timeout_sec, + .mode = COMMAND_ANY, + .usage = "riscv set_command_timeout_sec [sec]", + .help = "Set the wall-clock timeout (in seconds) for individual commands" + }, + { + .name = "set_reset_timeout_sec", + .handler = riscv_set_reset_timeout_sec, + .mode = COMMAND_ANY, + .usage = "riscv set_reset_timeout_sec [sec]", + .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration riscv_command_handlers[] = { + { + .name = "riscv", + .mode = COMMAND_ANY, + .help = "RISC-V Command Group", + .usage = "", + .chain = riscv_exec_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; struct target_type riscv_target = { @@ -1586,7 +1674,6 @@ int riscv_enumerate_triggers(struct target *target) tselect_rb &= ~(1ULL << (riscv_xlen(target)-1)); if (tselect_rb != t) break; - uint64_t tdata1 = riscv_get_register_on_hart(target, hartid, GDB_REGNO_TDATA1); int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); @@ -1612,98 +1699,6 @@ int riscv_enumerate_triggers(struct target *target) return ERROR_OK; } -/* Command Handlers */ - -COMMAND_HANDLER(riscv_test_compliance) { - - struct target *target = get_current_target(CMD_CTX); - - RISCV_INFO(r); - - if (CMD_ARGC > 0) { - LOG_ERROR("Command does not take any parameters."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (r->test_compliance) { - return r->test_compliance(target); - } else { - LOG_ERROR("This target does not support this command (may implement an older version of the spec)."); - return ERROR_FAIL; - } - -} - -COMMAND_HANDLER(riscv_set_command_timeout_sec) { - - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - int timeout = atoi(CMD_ARGV[0]); - if (timeout <= 0){ - LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); - return ERROR_FAIL; - } - - riscv_command_timeout_sec = timeout; - - return ERROR_OK; -} - -COMMAND_HANDLER(riscv_set_reset_timeout_sec) { - - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - int timeout = atoi(CMD_ARGV[0]); - if (timeout <= 0){ - LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); - return ERROR_FAIL; - } - - riscv_reset_timeout_sec = timeout; - return ERROR_OK; -} - - -static const struct command_registration riscv_exec_command_handlers[] = { - { - .name = "test_compliance", - .handler = riscv_test_compliance, - .mode = COMMAND_EXEC, - .usage = "riscv test_compliance", - .help = "Runs a basic compliance test suite against the RISC-V Debug Spec." - }, - { - .name = "set_command_timeout_sec", - .handler = riscv_set_command_timeout_sec, - .mode = COMMAND_ANY, - .usage = "riscv set_command_timeout_sec [sec]", - .help = "Set the wall-clock timeout (in seconds) for individual commands" - }, - { - .name = "set_reset_timeout_sec", - .handler = riscv_set_reset_timeout_sec, - .mode = COMMAND_ANY, - .usage = "riscv set_reset_timeout_sec [sec]", - .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" - }, - COMMAND_REGISTRATION_DONE -}; - -const struct command_registration riscv_command_handlers[] = { - { - .name = "riscv", - .mode = COMMAND_ANY, - .help = "RISC-V Command Group", - .usage = "", - .chain = riscv_exec_command_handlers - }, - COMMAND_REGISTRATION_DONE -}; - const char *gdb_regno_name(enum gdb_regno regno) { static char buf[32];