Make OpenOCD work when there is no program buffer.

Fixed abstract register access for registers that aren't XLEN wide.
Avoided excessive errors cases where we attempted to execute a fence but
failed.
Don't mark all the CSRs as caller-save. gdb was saving/restoring
dscratch, which broke function calls as a side effect. dscratch is
accessible for people who really know what they're doing, but gdb should
never quietly access it. The same is probably true for other CSRs.

Change-Id: I7bcdbbcb7e3c22ad92cbc205bf537c1fe548b160
This commit is contained in:
Tim Newsome 2018-01-31 15:33:45 -08:00
parent ee93a9b2f1
commit bb2c25c5ce
2 changed files with 68 additions and 30 deletions

View File

@ -611,14 +611,14 @@ static int execute_abstract_command(struct target *target, uint32_t command)
return ERROR_OK; return ERROR_OK;
} }
static riscv_reg_t read_abstract_arg(struct target *target, unsigned index) static riscv_reg_t read_abstract_arg(struct target *target, unsigned index,
unsigned size_bits)
{ {
riscv_reg_t value = 0; riscv_reg_t value = 0;
unsigned xlen = riscv_xlen(target); unsigned offset = index * size_bits / 32;
unsigned offset = index * xlen / 32; switch (size_bits) {
switch (xlen) {
default: default:
LOG_ERROR("Unsupported xlen: %d", xlen); LOG_ERROR("Unsupported size: %d", size_bits);
return ~0; return ~0;
case 64: case 64:
value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32; value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32;
@ -629,14 +629,13 @@ static riscv_reg_t read_abstract_arg(struct target *target, unsigned index)
} }
static int write_abstract_arg(struct target *target, unsigned index, static int write_abstract_arg(struct target *target, unsigned index,
riscv_reg_t value) riscv_reg_t value, unsigned size_bits)
{ {
unsigned xlen = riscv_xlen(target); unsigned offset = index * size_bits / 32;
unsigned offset = index * xlen / 32; switch (size_bits) {
switch (xlen) {
default: default:
LOG_ERROR("Unsupported xlen: %d", xlen); LOG_ERROR("Unsupported size: %d", size_bits);
return ~0; return ERROR_FAIL;
case 64: case 64:
dmi_write(target, DMI_DATA0 + offset + 1, value >> 32); dmi_write(target, DMI_DATA0 + offset + 1, value >> 32);
case 32: case 32:
@ -687,7 +686,7 @@ static int register_read_abstract(struct target *target, uint64_t *value,
RISCV013_INFO(info); RISCV013_INFO(info);
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
!info->abstract_read_fpr_supported) !info->abstract_write_fpr_supported)
return ERROR_FAIL; return ERROR_FAIL;
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
!info->abstract_read_csr_supported) !info->abstract_read_csr_supported)
@ -711,7 +710,7 @@ static int register_read_abstract(struct target *target, uint64_t *value,
} }
if (value) if (value)
*value = read_abstract_arg(target, 0); *value = read_abstract_arg(target, 0, size);
return ERROR_OK; return ERROR_OK;
} }
@ -732,7 +731,7 @@ static int register_write_abstract(struct target *target, uint32_t number,
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_TRANSFER |
AC_ACCESS_REGISTER_WRITE); AC_ACCESS_REGISTER_WRITE);
if (write_abstract_arg(target, 0, value) != ERROR_OK) if (write_abstract_arg(target, 0, value, size) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
int result = execute_abstract_command(target, command); int result = execute_abstract_command(target, command);
@ -946,16 +945,31 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch,
return ERROR_OK; return ERROR_OK;
} }
/** Return register size in bits. */
static unsigned register_size(struct target *target, unsigned number)
{
/* If reg_cache hasn't been initialized yet, make a guess. We need this for
* when this function is called during examine(). */
if (target->reg_cache)
return target->reg_cache->reg_list[number].size;
else
return riscv_xlen(target);
}
static int register_write_direct(struct target *target, unsigned number, static int register_write_direct(struct target *target, unsigned number,
uint64_t value) uint64_t value)
{ {
RISCV013_INFO(info);
RISCV_INFO(r);
LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target), LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target),
number, value); number, value);
int result = register_write_abstract(target, number, value, int result = register_write_abstract(target, number, value,
riscv_xlen(target)); register_size(target, number));
if (result == ERROR_OK) if (result == ERROR_OK ||
return ERROR_OK; info->progbufsize + r->impebreak < 2)
return result;
struct riscv_program program; struct riscv_program program;
riscv_program_init(&program, target); riscv_program_init(&program, target);
@ -1011,10 +1025,14 @@ static int register_write_direct(struct target *target, unsigned number,
/** Actually read registers from the target right now. */ /** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{ {
int result = register_read_abstract(target, value, number, RISCV013_INFO(info);
riscv_xlen(target)); RISCV_INFO(r);
if (result != ERROR_OK) { int result = register_read_abstract(target, value, number,
register_size(target, number));
if (result != ERROR_OK &&
info->progbufsize + r->impebreak >= 2) {
assert(number != GDB_REGNO_S0); assert(number != GDB_REGNO_S0);
struct riscv_program program; struct riscv_program program;
@ -1224,9 +1242,18 @@ static int examine(struct target *target)
info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE);
LOG_INFO("datacount=%d progbufsize=%d", info->datacount, info->progbufsize);
RISCV_INFO(r); RISCV_INFO(r);
r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK);
if (info->progbufsize + r->impebreak < 2) {
LOG_WARNING("We won't be able to execute fence instructions on this "
"target. Memory may not always appear consistent. "
"(progbufsize=%d, impebreak=%d)", info->progbufsize,
r->impebreak);
}
/* Before doing anything else we must first enumerate the harts. */ /* Before doing anything else we must first enumerate the harts. */
/* Don't call any riscv_* functions until after we've counted the number of /* Don't call any riscv_* functions until after we've counted the number of
@ -2400,14 +2427,26 @@ int riscv013_dmi_write_u64_bits(struct target *target)
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
} }
static int maybe_execute_fence_i(struct target *target)
{
RISCV013_INFO(info);
RISCV_INFO(r);
if (info->progbufsize + r->impebreak >= 2) {
struct riscv_program program;
riscv_program_init(&program, target);
if (riscv_program_fence_i(&program) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_exec(&program, target) != ERROR_OK)
return ERROR_FAIL;
}
return ERROR_OK;
}
/* Helper Functions. */ /* Helper Functions. */
static int riscv013_on_step_or_resume(struct target *target, bool step) static int riscv013_on_step_or_resume(struct target *target, bool step)
{ {
struct riscv_program program; if (maybe_execute_fence_i(target) != ERROR_OK)
riscv_program_init(&program, target); return ERROR_FAIL;
riscv_program_fence_i(&program);
if (riscv_program_exec(&program, target) != ERROR_OK)
LOG_ERROR("Unable to execute fence.i");
/* We want to twiddle some bits in the debug CSR so debugging works. */ /* We want to twiddle some bits in the debug CSR so debugging works. */
riscv_reg_t dcsr; riscv_reg_t dcsr;
@ -2430,10 +2469,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step
return ERROR_FAIL; return ERROR_FAIL;
} }
struct riscv_program program; if (maybe_execute_fence_i(target) != ERROR_OK)
riscv_program_init(&program, target);
riscv_program_fence_i(&program);
if (riscv_program_exec(&program, target) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Issue the resume command, and then wait for the current hart to resume. */ /* Issue the resume command, and then wait for the current hart to resume. */

View File

@ -1884,7 +1884,6 @@ int riscv_init_registers(struct target *target)
* between). */ * between). */
for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) {
struct reg *r = &target->reg_cache->reg_list[number]; struct reg *r = &target->reg_cache->reg_list[number];
r->caller_save = true;
r->dirty = false; r->dirty = false;
r->valid = false; r->valid = false;
r->exist = true; r->exist = true;
@ -1896,6 +1895,7 @@ int riscv_init_registers(struct target *target)
* target is in theory allowed to change XLEN on us. But I expect a lot * target is in theory allowed to change XLEN on us. But I expect a lot
* of other things to break in that case as well. */ * of other things to break in that case as well. */
if (number <= GDB_REGNO_XPR31) { if (number <= GDB_REGNO_XPR31) {
r->caller_save = true;
switch (number) { switch (number) {
case GDB_REGNO_ZERO: case GDB_REGNO_ZERO:
r->name = "zero"; r->name = "zero";
@ -1997,10 +1997,12 @@ int riscv_init_registers(struct target *target)
r->group = "general"; r->group = "general";
r->feature = &feature_cpu; r->feature = &feature_cpu;
} else if (number == GDB_REGNO_PC) { } else if (number == GDB_REGNO_PC) {
r->caller_save = true;
sprintf(reg_name, "pc"); sprintf(reg_name, "pc");
r->group = "general"; r->group = "general";
r->feature = &feature_cpu; r->feature = &feature_cpu;
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
r->caller_save = true;
if (riscv_supports_extension(target, 'D')) { if (riscv_supports_extension(target, 'D')) {
r->reg_data_type = &type_ieee_double; r->reg_data_type = &type_ieee_double;
r->size = 64; r->size = 64;