aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/target/riscv/riscv-013.c221
1 files changed, 159 insertions, 62 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index fc7f3aa..7df035c 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -187,55 +187,60 @@ typedef struct {
// Some memoized values
int progbuf_size, progbuf_addr, data_addr, data_size;
+
+ bool abstract_read_csr_supported;
+ bool abstract_write_csr_supported;
+ bool abstract_read_fpr_supported;
+ bool abstract_write_fpr_supported;
} riscv013_info_t;
static void decode_dmi(char *text, unsigned address, unsigned data)
{
+ static const struct {
+ unsigned address;
+ uint64_t mask;
+ const char *name;
+ } description[] = {
+ { DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ANYNONEXISTENT, "anynonexistent" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ALLUNAVAIL, "allunavail" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ANYUNAVAIL, "anyunavail" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ALLRUNNING, "allrunning" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ANYRUNNING, "anyrunning" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ALLHALTED, "allhalted" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_ANYHALTED, "anyhalted" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_CFGSTRVALID, "cfgstrvalid" },
+ { DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" },
+
+ { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" },
+ { DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" },
+ { DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" },
+ { DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" },
+
+ { DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" },
+ };
+
text[0] = 0;
- switch (address) {
- case DMI_DMSTATUS:
- if (get_field(data, DMI_DMSTATUS_ALLRESUMEACK)) {
- strcat(text, " allresumeack");
- }
- if (get_field(data, DMI_DMSTATUS_ANYRESUMEACK)) {
- strcat(text, " anyresumeack");
- }
- if (get_field(data, DMI_DMSTATUS_ALLNONEXISTENT)) {
- strcat(text, " allnonexistent");
- }
- if (get_field(data, DMI_DMSTATUS_ANYNONEXISTENT)) {
- strcat(text, " anynonexistent");
- }
- if (get_field(data, DMI_DMSTATUS_ALLUNAVAIL)) {
- strcat(text, " allunavail");
- }
- if (get_field(data, DMI_DMSTATUS_ANYUNAVAIL)) {
- strcat(text, " anyunavail");
- }
- if (get_field(data, DMI_DMSTATUS_ALLRUNNING)) {
- strcat(text, " allrunning");
- }
- if (get_field(data, DMI_DMSTATUS_ANYRUNNING)) {
- strcat(text, " anyrunning");
- }
- if (get_field(data, DMI_DMSTATUS_ALLHALTED)) {
- strcat(text, " allhalted");
- }
- if (get_field(data, DMI_DMSTATUS_ANYHALTED)) {
- strcat(text, " anyhalted");
- }
- if (get_field(data, DMI_DMSTATUS_AUTHENTICATED)) {
- strcat(text, " authenticated");
- }
- if (get_field(data, DMI_DMSTATUS_AUTHBUSY)) {
- strcat(text, " authbusy");
- }
- if (get_field(data, DMI_DMSTATUS_CFGSTRVALID)) {
- strcat(text, " cfgstrvalid");
+ for (unsigned i = 0; i < DIM(description); i++) {
+ if (description[i].address == address) {
+ uint64_t mask = description[i].mask;
+ unsigned value = get_field(data, mask);
+ if (value) {
+ if (i > 0)
+ *(text++) = ' ';
+ if (mask & (mask >> 1)) {
+ // If the field is more than 1 bit wide.
+ sprintf(text, "%s=%d", description[i].name, value);
+ } else {
+ strcpy(text, description[i].name);
+ }
+ text += strlen(text);
}
- sprintf(text + strlen(text), " version=%d", get_field(data,
- DMI_DMSTATUS_VERSION));
- break;
+ }
}
}
@@ -612,9 +617,109 @@ static int register_write_direct(struct target *target, unsigned number,
return ERROR_OK;
}
+static int execute_abstract_command(struct target *target, uint32_t command)
+{
+ LOG_DEBUG("command=0x%x", command);
+ dmi_write(target, DMI_COMMAND, command);
+
+ {
+ uint32_t dmstatus = 0;
+ wait_for_idle(target, &dmstatus);
+ }
+
+ uint32_t cs = dmi_read(target, DMI_ABSTRACTCS);
+ unsigned cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR);
+ if (cmderr != 0) {
+ LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs);
+ // Clear the error.
+ dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR,
+ cmderr));
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static uint64_t read_abstract_arg(struct target *target, unsigned index)
+{
+ uint64_t value = 0;
+ unsigned xlen = riscv_xlen(target);
+ unsigned offset = index * xlen / 32;
+ switch (xlen) {
+ default:
+ LOG_ERROR("Unsupported xlen: %d", xlen);
+ return ~0;
+ case 64:
+ value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32;
+ case 32:
+ value |= dmi_read(target, DMI_DATA0 + offset);
+ }
+ return value;
+}
+
+static int register_read_abstract(struct target *target, uint64_t *value,
+ uint32_t number, unsigned size)
+{
+ RISCV013_INFO(r);
+
+ uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
+ switch (size) {
+ case 32:
+ command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
+ break;
+ case 64:
+ command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
+ break;
+ default:
+ LOG_ERROR("Unsupported abstract register read size: %d", size);
+ return ERROR_FAIL;
+ }
+ command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0);
+ command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
+ command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0);
+
+ if (number <= GDB_REGNO_XPR31) {
+ command = set_field(command, AC_ACCESS_REGISTER_REGNO,
+ 0x1000 + number - GDB_REGNO_XPR0);
+ } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
+ if (!r->abstract_read_fpr_supported)
+ return ERROR_FAIL;
+ command = set_field(command, AC_ACCESS_REGISTER_REGNO,
+ 0x1020 + number - GDB_REGNO_FPR0);
+ } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
+ if (!r->abstract_read_csr_supported)
+ return ERROR_FAIL;
+ command = set_field(command, AC_ACCESS_REGISTER_REGNO,
+ number - GDB_REGNO_CSR0);
+ } else {
+ return ERROR_FAIL;
+ }
+
+ int result = execute_abstract_command(target, command);
+ if (result != ERROR_OK) {
+ if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
+ r->abstract_read_fpr_supported = false;
+ LOG_INFO("Disabling abstract command reads from FPRs.");
+ } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
+ r->abstract_read_csr_supported = false;
+ LOG_INFO("Disabling abstract command reads from CSRs.");
+ }
+ return result;
+ }
+
+ *value = read_abstract_arg(target, 0);
+
+ return ERROR_OK;
+}
+
/** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{
+ int result = register_read_abstract(target, value, number,
+ riscv_xlen(target));
+ if (result == ERROR_OK)
+ return ERROR_OK;
+
struct riscv_program program;
riscv_program_init(&program, target);
riscv_addr_t output = riscv_program_alloc_d(&program);
@@ -742,6 +847,13 @@ static int init_target(struct command_context *cmd_ctx,
info->dmi_busy_delay = 0;
info->ac_busy_delay = 0;
+ // Assume all these abstract commands are supported until we learn
+ // otherwise.
+ info->abstract_read_csr_supported = true;
+ info->abstract_write_csr_supported = true;
+ info->abstract_read_fpr_supported = true;
+ info->abstract_write_fpr_supported = true;
+
target->reg_cache = calloc(1, sizeof(*target->reg_cache));
target->reg_cache->name = "RISC-V Registers";
target->reg_cache->num_regs = GDB_REGNO_COUNT;
@@ -1207,9 +1319,9 @@ static int examine(struct target *target)
riscv_program_insert(&program64, sd(GDB_REGNO_S0, GDB_REGNO_S0, offset));
riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH);
riscv_program_fence(&program64);
- riscv_program_exec(&program64, target);
+ int result = riscv_program_exec(&program64, target);
- if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0) {
+ if (result == ERROR_OK) {
r->debug_buffer_addr[i] =
(dmi_read(target, DMI_PROGBUF0 + (8 + offset) / 4) << 32)
+ dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4)
@@ -1742,7 +1854,7 @@ struct target_type riscv013_target =
.arch_state = arch_state,
};
-/*** 0.13-specific implementations of various RISC-V hepler functions. ***/
+/*** 0.13-specific implementations of various RISC-V helper functions. ***/
static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid)
{
LOG_DEBUG("reading register 0x%08x on hart %d", rid, hid);
@@ -1914,28 +2026,13 @@ riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index)
int riscv013_execute_debug_buffer(struct target *target)
{
- riscv013_clear_abstract_error(target);
-
uint32_t run_program = 0;
run_program = set_field(run_program, AC_ACCESS_REGISTER_SIZE, 2);
run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1);
run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0);
run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000);
- dmi_write(target, DMI_COMMAND, run_program);
- {
- uint32_t dmstatus = 0;
- wait_for_idle(target, &dmstatus);
- }
-
- uint32_t cs = dmi_read(target, DMI_ABSTRACTCS);
- if (get_field(cs, DMI_ABSTRACTCS_CMDERR) != 0) {
- LOG_ERROR("unable to execute program: (abstractcs=0x%08x)", cs);
- dmi_read(target, DMI_DMSTATUS);
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
+ return execute_abstract_command(target, run_program);
}
void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d)