Skip to content

Commit f37e93b

Browse files
committed
Try using abstract commands to read registers
This is the only way the spec guarantees that GPRs are accessible, and depending on the implementation this might be the only way that CSRs are accessible. Also changed the debug code that parses out DMI fields to be simpler to maintain (albeit a little slower). riscv013_execute_debug_buffer() now automatically clears cmderr if the command fails. That feels like the right behavior. (It does return the error to its caller.)
1 parent da74f51 commit f37e93b

File tree

1 file changed

+159
-62
lines changed

1 file changed

+159
-62
lines changed

src/target/riscv/riscv-013.c

Lines changed: 159 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -187,55 +187,60 @@ typedef struct {
187187

188188
// Some memoized values
189189
int progbuf_size, progbuf_addr, data_addr, data_size;
190+
191+
bool abstract_read_csr_supported;
192+
bool abstract_write_csr_supported;
193+
bool abstract_read_fpr_supported;
194+
bool abstract_write_fpr_supported;
190195
} riscv013_info_t;
191196

192197
static void decode_dmi(char *text, unsigned address, unsigned data)
193198
{
199+
static const struct {
200+
unsigned address;
201+
uint64_t mask;
202+
const char *name;
203+
} description[] = {
204+
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" },
205+
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" },
206+
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" },
207+
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYNONEXISTENT, "anynonexistent" },
208+
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLUNAVAIL, "allunavail" },
209+
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYUNAVAIL, "anyunavail" },
210+
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLRUNNING, "allrunning" },
211+
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYRUNNING, "anyrunning" },
212+
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLHALTED, "allhalted" },
213+
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYHALTED, "anyhalted" },
214+
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" },
215+
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" },
216+
{ DMI_DMSTATUS, DMI_DMSTATUS_CFGSTRVALID, "cfgstrvalid" },
217+
{ DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" },
218+
219+
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" },
220+
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" },
221+
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" },
222+
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" },
223+
224+
{ DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" },
225+
};
226+
194227
text[0] = 0;
195-
switch (address) {
196-
case DMI_DMSTATUS:
197-
if (get_field(data, DMI_DMSTATUS_ALLRESUMEACK)) {
198-
strcat(text, " allresumeack");
199-
}
200-
if (get_field(data, DMI_DMSTATUS_ANYRESUMEACK)) {
201-
strcat(text, " anyresumeack");
202-
}
203-
if (get_field(data, DMI_DMSTATUS_ALLNONEXISTENT)) {
204-
strcat(text, " allnonexistent");
205-
}
206-
if (get_field(data, DMI_DMSTATUS_ANYNONEXISTENT)) {
207-
strcat(text, " anynonexistent");
208-
}
209-
if (get_field(data, DMI_DMSTATUS_ALLUNAVAIL)) {
210-
strcat(text, " allunavail");
211-
}
212-
if (get_field(data, DMI_DMSTATUS_ANYUNAVAIL)) {
213-
strcat(text, " anyunavail");
214-
}
215-
if (get_field(data, DMI_DMSTATUS_ALLRUNNING)) {
216-
strcat(text, " allrunning");
217-
}
218-
if (get_field(data, DMI_DMSTATUS_ANYRUNNING)) {
219-
strcat(text, " anyrunning");
220-
}
221-
if (get_field(data, DMI_DMSTATUS_ALLHALTED)) {
222-
strcat(text, " allhalted");
223-
}
224-
if (get_field(data, DMI_DMSTATUS_ANYHALTED)) {
225-
strcat(text, " anyhalted");
226-
}
227-
if (get_field(data, DMI_DMSTATUS_AUTHENTICATED)) {
228-
strcat(text, " authenticated");
229-
}
230-
if (get_field(data, DMI_DMSTATUS_AUTHBUSY)) {
231-
strcat(text, " authbusy");
232-
}
233-
if (get_field(data, DMI_DMSTATUS_CFGSTRVALID)) {
234-
strcat(text, " cfgstrvalid");
228+
for (unsigned i = 0; i < DIM(description); i++) {
229+
if (description[i].address == address) {
230+
uint64_t mask = description[i].mask;
231+
unsigned value = get_field(data, mask);
232+
if (value) {
233+
if (i > 0)
234+
*(text++) = ' ';
235+
if (mask & (mask >> 1)) {
236+
// If the field is more than 1 bit wide.
237+
sprintf(text, "%s=%d", description[i].name, value);
238+
} else {
239+
strcpy(text, description[i].name);
240+
}
241+
text += strlen(text);
235242
}
236-
sprintf(text + strlen(text), " version=%d", get_field(data,
237-
DMI_DMSTATUS_VERSION));
238-
break;
243+
}
239244
}
240245
}
241246

@@ -612,9 +617,109 @@ static int register_write_direct(struct target *target, unsigned number,
612617
return ERROR_OK;
613618
}
614619

620+
static int execute_abstract_command(struct target *target, uint32_t command)
621+
{
622+
LOG_DEBUG("command=0x%x", command);
623+
dmi_write(target, DMI_COMMAND, command);
624+
625+
{
626+
uint32_t dmstatus = 0;
627+
wait_for_idle(target, &dmstatus);
628+
}
629+
630+
uint32_t cs = dmi_read(target, DMI_ABSTRACTCS);
631+
unsigned cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR);
632+
if (cmderr != 0) {
633+
LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs);
634+
// Clear the error.
635+
dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR,
636+
cmderr));
637+
return ERROR_FAIL;
638+
}
639+
640+
return ERROR_OK;
641+
}
642+
643+
static uint64_t read_abstract_arg(struct target *target, unsigned index)
644+
{
645+
uint64_t value = 0;
646+
unsigned xlen = riscv_xlen(target);
647+
unsigned offset = index * xlen / 32;
648+
switch (xlen) {
649+
default:
650+
LOG_ERROR("Unsupported xlen: %d", xlen);
651+
return ~0;
652+
case 64:
653+
value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32;
654+
case 32:
655+
value |= dmi_read(target, DMI_DATA0 + offset);
656+
}
657+
return value;
658+
}
659+
660+
static int register_read_abstract(struct target *target, uint64_t *value,
661+
uint32_t number, unsigned size)
662+
{
663+
RISCV013_INFO(r);
664+
665+
uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
666+
switch (size) {
667+
case 32:
668+
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
669+
break;
670+
case 64:
671+
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
672+
break;
673+
default:
674+
LOG_ERROR("Unsupported abstract register read size: %d", size);
675+
return ERROR_FAIL;
676+
}
677+
command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0);
678+
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
679+
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0);
680+
681+
if (number <= GDB_REGNO_XPR31) {
682+
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
683+
0x1000 + number - GDB_REGNO_XPR0);
684+
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
685+
if (!r->abstract_read_fpr_supported)
686+
return ERROR_FAIL;
687+
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
688+
0x1020 + number - GDB_REGNO_FPR0);
689+
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
690+
if (!r->abstract_read_csr_supported)
691+
return ERROR_FAIL;
692+
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
693+
number - GDB_REGNO_CSR0);
694+
} else {
695+
return ERROR_FAIL;
696+
}
697+
698+
int result = execute_abstract_command(target, command);
699+
if (result != ERROR_OK) {
700+
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
701+
r->abstract_read_fpr_supported = false;
702+
LOG_INFO("Disabling abstract command reads from FPRs.");
703+
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
704+
r->abstract_read_csr_supported = false;
705+
LOG_INFO("Disabling abstract command reads from CSRs.");
706+
}
707+
return result;
708+
}
709+
710+
*value = read_abstract_arg(target, 0);
711+
712+
return ERROR_OK;
713+
}
714+
615715
/** Actually read registers from the target right now. */
616716
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
617717
{
718+
int result = register_read_abstract(target, value, number,
719+
riscv_xlen(target));
720+
if (result == ERROR_OK)
721+
return ERROR_OK;
722+
618723
struct riscv_program program;
619724
riscv_program_init(&program, target);
620725
riscv_addr_t output = riscv_program_alloc_d(&program);
@@ -742,6 +847,13 @@ static int init_target(struct command_context *cmd_ctx,
742847
info->dmi_busy_delay = 0;
743848
info->ac_busy_delay = 0;
744849

850+
// Assume all these abstract commands are supported until we learn
851+
// otherwise.
852+
info->abstract_read_csr_supported = true;
853+
info->abstract_write_csr_supported = true;
854+
info->abstract_read_fpr_supported = true;
855+
info->abstract_write_fpr_supported = true;
856+
745857
target->reg_cache = calloc(1, sizeof(*target->reg_cache));
746858
target->reg_cache->name = "RISC-V Registers";
747859
target->reg_cache->num_regs = GDB_REGNO_COUNT;
@@ -1207,9 +1319,9 @@ static int examine(struct target *target)
12071319
riscv_program_insert(&program64, sd(GDB_REGNO_S0, GDB_REGNO_S0, offset));
12081320
riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH);
12091321
riscv_program_fence(&program64);
1210-
riscv_program_exec(&program64, target);
1322+
int result = riscv_program_exec(&program64, target);
12111323

1212-
if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0) {
1324+
if (result == ERROR_OK) {
12131325
r->debug_buffer_addr[i] =
12141326
(dmi_read(target, DMI_PROGBUF0 + (8 + offset) / 4) << 32)
12151327
+ dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4)
@@ -1742,7 +1854,7 @@ struct target_type riscv013_target =
17421854
.arch_state = arch_state,
17431855
};
17441856

1745-
/*** 0.13-specific implementations of various RISC-V hepler functions. ***/
1857+
/*** 0.13-specific implementations of various RISC-V helper functions. ***/
17461858
static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid)
17471859
{
17481860
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)
19142026

19152027
int riscv013_execute_debug_buffer(struct target *target)
19162028
{
1917-
riscv013_clear_abstract_error(target);
1918-
19192029
uint32_t run_program = 0;
19202030
run_program = set_field(run_program, AC_ACCESS_REGISTER_SIZE, 2);
19212031
run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1);
19222032
run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0);
19232033
run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000);
1924-
dmi_write(target, DMI_COMMAND, run_program);
19252034

1926-
{
1927-
uint32_t dmstatus = 0;
1928-
wait_for_idle(target, &dmstatus);
1929-
}
1930-
1931-
uint32_t cs = dmi_read(target, DMI_ABSTRACTCS);
1932-
if (get_field(cs, DMI_ABSTRACTCS_CMDERR) != 0) {
1933-
LOG_ERROR("unable to execute program: (abstractcs=0x%08x)", cs);
1934-
dmi_read(target, DMI_DMSTATUS);
1935-
return ERROR_FAIL;
1936-
}
1937-
1938-
return ERROR_OK;
2035+
return execute_abstract_command(target, run_program);
19392036
}
19402037

19412038
void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d)

0 commit comments

Comments
 (0)