Upstream a whole host of RISC-V changes.

Made no attempt to separate this out into reviewable chunks, since this
is all RISC-V-specific code developed at
https://github.com/riscv/riscv-openocd

Memory sample and repeat read functionality was left out of this change
since it requires some target-independent changes that I'll upstream
some other time.

Change-Id: I92917c86d549c232cbf36ffbfefc93331c05accd
Signed-off-by: Tim Newsome <tim@sifive.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6529
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Tim Newsome 2021-09-01 15:00:46 -07:00 committed by Antonio Borneo
parent f4612e06c6
commit 615709d140
9 changed files with 2617 additions and 1655 deletions

View File

@ -27,23 +27,33 @@ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_
out->allocated_scans = scans;
out->idle_count = idle;
out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE);
if (!out->data_out)
if (!out->data_out) {
LOG_ERROR("Failed to allocate data_out in RISC-V batch.");
goto error1;
};
out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
if (!out->data_in)
if (!out->data_in) {
LOG_ERROR("Failed to allocate data_in in RISC-V batch.");
goto error2;
}
out->fields = malloc(sizeof(*out->fields) * (scans));
if (!out->fields)
if (!out->fields) {
LOG_ERROR("Failed to allocate fields in RISC-V batch.");
goto error3;
}
if (bscan_tunnel_ir_width != 0) {
out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
if (!out->bscan_ctxt)
if (!out->bscan_ctxt) {
LOG_ERROR("Failed to allocate bscan_ctxt in RISC-V batch.");
goto error4;
}
}
out->last_scan = RISCV_SCAN_TYPE_INVALID;
out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
if (!out->read_keys)
if (!out->read_keys) {
LOG_ERROR("Failed to allocate read_keys in RISC-V batch.");
goto error5;
}
return out;
error5:
@ -82,8 +92,6 @@ int riscv_batch_run(struct riscv_batch *batch)
return ERROR_OK;
}
keep_alive();
riscv_batch_add_nop(batch);
for (size_t i = 0; i < batch->used_scans; ++i) {
@ -96,11 +104,15 @@ int riscv_batch_run(struct riscv_batch *batch)
jtag_add_runtest(batch->idle_count, TAP_IDLE);
}
keep_alive();
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("Unable to execute JTAG queue");
return ERROR_FAIL;
}
keep_alive();
if (bscan_tunnel_ir_width != 0) {
/* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
for (size_t i = 0; i < batch->used_scans; ++i)

File diff suppressed because it is too large Load Diff

View File

@ -17,214 +17,202 @@ static uint32_t bit(uint32_t value, unsigned int b)
return (value >> b) & 1;
}
static uint32_t inst_rd(uint32_t r) __attribute__ ((unused));
static uint32_t inst_rd(uint32_t r)
{
return bits(r, 4, 0) << 7;
}
static uint32_t inst_rs1(uint32_t r) __attribute__ ((unused));
static uint32_t inst_rs1(uint32_t r)
{
return bits(r, 4, 0) << 15;
}
static uint32_t inst_rs2(uint32_t r) __attribute__ ((unused));
static uint32_t inst_rs2(uint32_t r)
{
return bits(r, 4, 0) << 20;
}
static uint32_t imm_i(uint32_t imm) __attribute__ ((unused));
static uint32_t imm_i(uint32_t imm)
{
return bits(imm, 11, 0) << 20;
}
static uint32_t imm_s(uint32_t imm) __attribute__ ((unused));
static uint32_t imm_s(uint32_t imm)
{
return (bits(imm, 4, 0) << 7) | (bits(imm, 11, 5) << 25);
}
static uint32_t imm_b(uint32_t imm) __attribute__ ((unused));
static uint32_t imm_b(uint32_t imm)
{
return (bit(imm, 11) << 7) | (bits(imm, 4, 1) << 8) | (bits(imm, 10, 5) << 25) | (bit(imm, 12) << 31);
}
static uint32_t imm_u(uint32_t imm) __attribute__ ((unused));
static uint32_t imm_u(uint32_t imm)
{
return bits(imm, 31, 12) << 12;
}
static uint32_t imm_j(uint32_t imm) __attribute__ ((unused));
static uint32_t imm_j(uint32_t imm)
{
return (bits(imm, 19, 12) << 12) | (bit(imm, 11) << 20) | (bits(imm, 10, 1) << 21) | (bit(imm, 20) << 31);
}
static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
static uint32_t jal(unsigned int rd, uint32_t imm)
{
return (bit(imm, 20) << 31) |
(bits(imm, 10, 1) << 21) |
(bit(imm, 11) << 20) |
(bits(imm, 19, 12) << 12) |
(rd << 7) |
MATCH_JAL;
return imm_j(imm) | inst_rd(rd) | MATCH_JAL;
}
static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
static uint32_t csrsi(unsigned int csr, uint16_t imm)
{
return (csr << 20) |
(bits(imm, 4, 0) << 15) |
MATCH_CSRRSI;
return imm_i(csr) | inst_rs1(imm) | MATCH_CSRRSI;
}
static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 5) << 25) |
(src << 20) |
(base << 15) |
(bits(offset, 4, 0) << 7) |
MATCH_SW;
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SW;
}
static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 5) << 25) |
(src << 20) |
(base << 15) |
(bits(offset, 4, 0) << 7) |
MATCH_SD;
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SD;
}
static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 5) << 25) |
(src << 20) |
(base << 15) |
(bits(offset, 4, 0) << 7) |
MATCH_SH;
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SH;
}
static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 5) << 25) |
(src << 20) |
(base << 15) |
(bits(offset, 4, 0) << 7) |
MATCH_SB;
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SB;
}
static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(rd, 4, 0) << 7) |
MATCH_LD;
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LD;
}
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(rd, 4, 0) << 7) |
MATCH_LW;
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LW;
}
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(rd, 4, 0) << 7) |
MATCH_LH;
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LH;
}
static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(rd, 4, 0) << 7) |
MATCH_LB;
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LB;
}
static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
static uint32_t csrw(unsigned int source, unsigned int csr)
{
return (csr << 20) | (source << 15) | MATCH_CSRRW;
return imm_i(csr) | inst_rs1(source) | MATCH_CSRRW;
}
static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
{
return (bits(imm, 11, 0) << 20) |
(src << 15) |
(dest << 7) |
MATCH_ADDI;
return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_ADDI;
}
static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
static uint32_t csrr(unsigned int rd, unsigned int csr)
{
return (csr << 20) | (rd << 7) | MATCH_CSRRS;
return imm_i(csr) | inst_rd(rd) | MATCH_CSRRS;
}
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
{
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS;
return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRS;
}
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr)
{
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW;
return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRW;
}
static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused));
static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr)
{
return (csr << 20) | (zimm << 15) | (rd << 7) | MATCH_CSRRCI;
return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | MATCH_CSRRCI;
}
static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused));
static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr)
{
return (csr << 20) | (zimm << 15) | (rd << 7) | MATCH_CSRRSI;
return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | MATCH_CSRRSI;
}
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 5) << 25) |
(bits(src, 4, 0) << 20) |
(base << 15) |
(bits(offset, 4, 0) << 7) |
MATCH_FSW;
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSW;
}
static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 5) << 25) |
(bits(src, 4, 0) << 20) |
(base << 15) |
(bits(offset, 4, 0) << 7) |
MATCH_FSD;
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSD;
}
static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(dest, 4, 0) << 7) |
MATCH_FLW;
return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLW;
}
static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(dest, 4, 0) << 7) |
MATCH_FLD;
return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLD;
}
static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused));
static uint32_t fmv_x_w(unsigned dest, unsigned src)
{
return src << 15 |
dest << 7 |
MATCH_FMV_X_W;
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_W;
}
static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused));
static uint32_t fmv_x_d(unsigned dest, unsigned src)
{
return src << 15 |
dest << 7 |
MATCH_FMV_X_D;
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_D;
}
static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused));
static uint32_t fmv_w_x(unsigned dest, unsigned src)
{
return src << 15 |
dest << 7 |
MATCH_FMV_W_X;
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_W_X;
}
static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused));
static uint32_t fmv_d_x(unsigned dest, unsigned src)
{
return src << 15 |
dest << 7 |
MATCH_FMV_D_X;
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_D_X;
}
static uint32_t ebreak(void) __attribute__ ((unused));
@ -250,9 +238,7 @@ static uint32_t fence_i(void)
static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
static uint32_t lui(unsigned int dest, uint32_t imm)
{
return (bits(imm, 19, 0) << 12) |
(dest << 7) |
MATCH_LUI;
return imm_u(imm) | inst_rd(dest) | MATCH_LUI;
}
/*
@ -299,19 +285,13 @@ static uint32_t nop(void)
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
{
return (bits(imm, 11, 0) << 20) |
(src << 15) |
(dest << 7) |
MATCH_XORI;
return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_XORI;
}
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused));
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
{
return (bits(shamt, 4, 0) << 20) |
(src << 15) |
(dest << 7) |
MATCH_SRLI;
return inst_rs2(shamt) | inst_rs1(src) | inst_rd(dest) | MATCH_SRLI;
}
static uint32_t fence(void) __attribute__((unused));
@ -323,28 +303,25 @@ static uint32_t fence(void)
static uint32_t auipc(unsigned int dest) __attribute__((unused));
static uint32_t auipc(unsigned int dest)
{
return MATCH_AUIPC | (dest << 7);
return MATCH_AUIPC | inst_rd(dest);
}
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) __attribute__((unused));
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm)
{
return (bits(imm, 10, 0) << 20) |
(src << 15) |
(dest << 7) |
MATCH_VSETVLI;
return (bits(imm, 10, 0) << 20) | inst_rs1(src) | inst_rd(dest) | MATCH_VSETVLI;
}
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) __attribute__((unused));
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2)
{
return (vs2 << 20) | (rd << 7) | MATCH_VMV_X_S;
return inst_rs2(vs2) | inst_rd(rd) | MATCH_VMV_X_S;
}
static uint32_t vmv_s_x(unsigned int vd, unsigned int vs2) __attribute__((unused));
static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1)
{
return (rs1 << 15) | (vd << 7) | MATCH_VMV_S_X;
return inst_rs1(rs1) | inst_rd(vd) | MATCH_VMV_S_X;
}
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
@ -352,6 +329,6 @@ static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
unsigned int rs1, unsigned int vm)
{
return (vm << 25) | (vs2 << 20) | (rs1 << 15) | (vd << 7) |
MATCH_VSLIDE1DOWN_VX;
return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX;
}

View File

@ -40,20 +40,10 @@ int riscv_program_write(struct riscv_program *program);
* program to execute. That's OK, just make sure this eventually terminates.
* */
int riscv_program_exec(struct riscv_program *p, struct target *t);
int riscv_program_load(struct riscv_program *p, struct target *t);
/* Clears a program, removing all the state associated with it. */
int riscv_program_clear(struct riscv_program *p, struct target *t);
/* A lower level interface, you shouldn't use this unless you have a reason. */
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i);
/* There is hardware support for saving at least one register. This register
* doesn't need to be saved/restored the usual way, which is useful during
* early initialization when we can't save/restore arbitrary registerrs to host
* memory. */
int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save);
/* Helpers to assemble various instructions. Return 0 on success. These might
* assemble into a multi-instruction sequence that overwrites some other
* register, but those will be properly saved and restored. */

View File

@ -152,6 +152,9 @@ typedef enum slot {
#define DMINFO_AUTHTYPE (3<<2)
#define DMINFO_VERSION 3
#define DMAUTHDATA0 0x12
#define DMAUTHDATA1 0x13
/*** Info about the core being debugged. ***/
#define DBUS_ADDRESS_UNKNOWN 0xffff
@ -216,8 +219,7 @@ typedef struct {
static int poll_target(struct target *target, bool announce);
static int riscv011_poll(struct target *target);
static int get_register(struct target *target, riscv_reg_t *value, int hartid,
int regid);
static int get_register(struct target *target, riscv_reg_t *value, int regid);
/*** Utility functions. ***/
@ -226,6 +228,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
static riscv011_info_t *get_info(const struct target *target)
{
riscv_info_t *info = (riscv_info_t *) target->arch_info;
assert(info);
assert(info->version_specific);
return (riscv011_info_t *) info->version_specific;
}
@ -1230,7 +1234,7 @@ static int update_mstatus_actual(struct target *target)
/* Force reading the register. In that process mstatus_actual will be
* updated. */
riscv_reg_t mstatus;
return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS);
return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
}
/*** OpenOCD target functions. ***/
@ -1334,10 +1338,8 @@ static int register_write(struct target *target, unsigned int number,
return ERROR_OK;
}
static int get_register(struct target *target, riscv_reg_t *value, int hartid,
int regid)
static int get_register(struct target *target, riscv_reg_t *value, int regid)
{
assert(hartid == 0);
riscv011_info_t *info = get_info(target);
maybe_write_tselect(target);
@ -1380,10 +1382,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
return ERROR_OK;
}
static int set_register(struct target *target, int hartid, int regid,
uint64_t value)
static int set_register(struct target *target, int regid, uint64_t value)
{
assert(hartid == 0);
return register_write(target, regid, value);
}
@ -1523,7 +1523,7 @@ static int examine(struct target *target)
}
/* Pretend this is a 32-bit system until we have found out the true value. */
r->xlen[0] = 32;
r->xlen = 32;
/* Figure out XLEN, and test writing all of Debug RAM while we're at it. */
cache_set32(target, 0, xori(S1, ZERO, -1));
@ -1551,11 +1551,11 @@ static int examine(struct target *target)
uint32_t word1 = cache_get32(target, 1);
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
if (word0 == 1 && word1 == 0) {
generic_info->xlen[0] = 32;
generic_info->xlen = 32;
} else if (word0 == 0xffffffff && word1 == 3) {
generic_info->xlen[0] = 64;
generic_info->xlen = 64;
} else if (word0 == 0xffffffff && word1 == 0xffffffff) {
generic_info->xlen[0] = 128;
generic_info->xlen = 128;
} else {
uint32_t exception = cache_get32(target, info->dramsize-1);
LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
@ -1565,11 +1565,11 @@ static int examine(struct target *target)
}
LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
if (read_remote_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) {
const unsigned old_csr_misa = 0xf10;
LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
old_csr_misa);
if (read_remote_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) {
/* Maybe this is an old core that still has $misa at the old
* address. */
LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
@ -1591,7 +1591,7 @@ static int examine(struct target *target)
for (size_t i = 0; i < 32; ++i)
reg_cache_set(target, i, -1);
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
riscv_xlen(target), r->misa[0]);
riscv_xlen(target), r->misa);
return ERROR_OK;
}
@ -2294,21 +2294,95 @@ static int arch_state(struct target *target)
return ERROR_OK;
}
COMMAND_HELPER(riscv011_print_info, struct target *target)
{
/* Abstract description. */
riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0);
riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0);
riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0);
uint32_t dminfo = dbus_read(target, DMINFO);
riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED));
return 0;
}
static int wait_for_authbusy(struct target *target)
{
time_t start = time(NULL);
while (1) {
uint32_t dminfo = dbus_read(target, DMINFO);
if (!get_field(dminfo, DMINFO_AUTHBUSY))
break;
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
riscv_command_timeout_sec,
dminfo);
return ERROR_FAIL;
}
}
return ERROR_OK;
}
static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned int index)
{
if (index > 1) {
LOG_ERROR("Spec 0.11 only has a two authdata registers.");
return ERROR_FAIL;
}
if (wait_for_authbusy(target) != ERROR_OK)
return ERROR_FAIL;
uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
*value = dbus_read(target, authdata_address);
return ERROR_OK;
}
static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned int index)
{
if (index > 1) {
LOG_ERROR("Spec 0.11 only has a two authdata registers.");
return ERROR_FAIL;
}
if (wait_for_authbusy(target) != ERROR_OK)
return ERROR_FAIL;
uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
dbus_write(target, authdata_address, value);
return ERROR_OK;
}
static int init_target(struct command_context *cmd_ctx,
struct target *target)
{
LOG_DEBUG("init");
riscv_info_t *generic_info = (riscv_info_t *)target->arch_info;
RISCV_INFO(generic_info);
generic_info->get_register = get_register;
generic_info->set_register = set_register;
generic_info->read_memory = read_memory;
generic_info->authdata_read = &riscv011_authdata_read;
generic_info->authdata_write = &riscv011_authdata_write;
generic_info->print_info = &riscv011_print_info;
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
if (!generic_info->version_specific)
return ERROR_FAIL;
/* Assume 32-bit until we discover the real value in examine(). */
generic_info->xlen[0] = 32;
generic_info->xlen = 32;
riscv_init_registers(target);
return ERROR_OK;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@ struct riscv_program;
#include "gdb_regs.h"
#include "jtag/jtag.h"
#include "target/register.h"
#include <helper/command.h>
/* The register cache is statically allocated. */
#define RISCV_MAX_HARTS 1024
@ -26,6 +27,8 @@ struct riscv_program;
# define PG_MAX_LEVEL 4
#define RISCV_NUM_MEM_ACCESS_METHODS 3
extern struct target_type riscv011_target;
extern struct target_type riscv013_target;
@ -36,6 +39,13 @@ typedef uint64_t riscv_reg_t;
typedef uint32_t riscv_insn_t;
typedef uint64_t riscv_addr_t;
enum riscv_mem_access_method {
RISCV_MEM_ACCESS_UNSPECIFIED,
RISCV_MEM_ACCESS_PROGBUF,
RISCV_MEM_ACCESS_SYSBUS,
RISCV_MEM_ACCESS_ABSTRACT
};
enum riscv_halt_reason {
RISCV_HALT_INTERRUPT,
RISCV_HALT_BREAKPOINT,
@ -51,15 +61,35 @@ typedef struct {
unsigned custom_number;
} riscv_reg_info_t;
#define RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE 0x80
#define RISCV_SAMPLE_BUF_TIMESTAMP_AFTER 0x81
struct riscv_sample_buf {
uint8_t *buf;
unsigned int used;
unsigned int size;
};
typedef struct {
bool enabled;
struct {
bool enabled;
target_addr_t address;
uint32_t size_bytes;
} bucket[16];
} riscv_sample_config_t;
typedef struct {
struct list_head list;
uint16_t low, high;
char *name;
} range_list_t;
typedef struct {
unsigned dtm_version;
struct command_context *cmd_ctx;
void *version_specific;
/* The hart that the RTOS thinks is currently being debugged. */
int rtos_hartid;
/* The hart that is currently being debugged. Note that this is
* different than the hartid that the RTOS is expected to use. This
* one will change all the time, it's more of a global argument to
@ -76,13 +106,13 @@ typedef struct {
char *reg_names;
/* It's possible that each core has a different supported ISA set. */
int xlen[RISCV_MAX_HARTS];
riscv_reg_t misa[RISCV_MAX_HARTS];
int xlen;
riscv_reg_t misa;
/* Cached value of vlenb. 0 if vlenb is not readable for some reason. */
unsigned vlenb[RISCV_MAX_HARTS];
unsigned int vlenb;
/* The number of triggers per hart. */
unsigned trigger_count[RISCV_MAX_HARTS];
unsigned int trigger_count;
/* For each physical trigger, contains -1 if the hwbp is available, or the
* unique_id of the breakpoint/watchpoint that is using it.
@ -91,7 +121,7 @@ typedef struct {
int trigger_unique_id[RISCV_MAX_HWBPS];
/* The number of entries in the debug buffer. */
int debug_buffer_size[RISCV_MAX_HARTS];
int debug_buffer_size;
/* This avoids invalidating the register cache too often. */
bool registers_initialized;
@ -112,10 +142,8 @@ typedef struct {
/* Helper functions that target the various RISC-V debug spec
* implementations. */
int (*get_register)(struct target *target,
riscv_reg_t *value, int hid, int rid);
int (*set_register)(struct target *target, int hartid, int regid,
uint64_t value);
int (*get_register)(struct target *target, riscv_reg_t *value, int regid);
int (*set_register)(struct target *target, int regid, uint64_t value);
int (*get_register_buf)(struct target *target, uint8_t *buf, int regno);
int (*set_register_buf)(struct target *target, int regno,
const uint8_t *buf);
@ -143,8 +171,8 @@ typedef struct {
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
int (*authdata_read)(struct target *target, uint32_t *value);
int (*authdata_write)(struct target *target, uint32_t value);
int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index);
int (*authdata_write)(struct target *target, uint32_t value, unsigned int index);
int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address);
int (*dmi_write)(struct target *target, uint32_t address, uint32_t value);
@ -152,7 +180,10 @@ typedef struct {
int (*test_sba_config_reg)(struct target *target, target_addr_t legal_address,
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
int (*test_compliance)(struct target *target);
int (*sample_memory)(struct target *target,
struct riscv_sample_buf *buf,
riscv_sample_config_t *config,
int64_t until_ms);
int (*read_memory)(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
@ -161,6 +192,8 @@ typedef struct {
int (*hart_count)(struct target *target);
unsigned (*data_bits)(struct target *target);
COMMAND_HELPER((*print_info), struct target *target);
/* Storage for vector register types. */
struct reg_data_type_vector vector_uint8;
struct reg_data_type_vector vector_uint16;
@ -179,8 +212,31 @@ typedef struct {
/* Set when trigger registers are changed by the user. This indicates we eed
* to beware that we may hit a trigger that we didn't realize had been set. */
bool manual_hwbp_set;
/* Memory access methods to use, ordered by priority, highest to lowest. */
int mem_access_methods[RISCV_NUM_MEM_ACCESS_METHODS];
/* Different memory regions may need different methods but single configuration is applied
* for all. Following flags are used to warn only once about failing memory access method. */
bool mem_access_progbuf_warn;
bool mem_access_sysbus_warn;
bool mem_access_abstract_warn;
/* In addition to the ones in the standard spec, we'll also expose additional
* CSRs in this list. */
struct list_head expose_csr;
/* Same, but for custom registers.
* Custom registers are for non-standard extensions and use abstract register numbers
* from range 0xc000 ... 0xffff. */
struct list_head expose_custom;
riscv_sample_config_t sample_config;
struct riscv_sample_buf sample_buf;
} riscv_info_t;
COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,
unsigned int value);
typedef struct {
uint8_t tunneled_dr_width;
struct scan_field tunneled_dr[4];
@ -205,8 +261,6 @@ extern int riscv_command_timeout_sec;
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
extern int riscv_reset_timeout_sec;
extern bool riscv_prefer_sba;
extern bool riscv_enable_virtual;
extern bool riscv_ebreakm;
extern bool riscv_ebreaks;
@ -216,7 +270,10 @@ extern bool riscv_ebreaku;
* that provides that. */
static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));
static inline riscv_info_t *riscv_info(const struct target *target)
{ return target->arch_info; }
{
assert(target->arch_info);
return target->arch_info;
}
#define RISCV_INFO(R) riscv_info_t *R = riscv_info(target);
extern uint8_t ir_dtmcontrol[4];
@ -269,44 +326,30 @@ void riscv_info_init(struct target *target, riscv_info_t *r);
* then the only hart. */
int riscv_step_rtos_hart(struct target *target);
bool riscv_supports_extension(struct target *target, int hartid, char letter);
bool riscv_supports_extension(struct target *target, char letter);
/* Returns XLEN for the given (or current) hart. */
unsigned riscv_xlen(const struct target *target);
int riscv_xlen_of_hart(const struct target *target, int hartid);
bool riscv_rtos_enabled(const struct target *target);
int riscv_xlen_of_hart(const struct target *target);
/* Sets the current hart, which is the hart that will actually be used when
* issuing debug commands. */
int riscv_set_current_hartid(struct target *target, int hartid);
int riscv_select_current_hart(struct target *target);
int riscv_current_hartid(const struct target *target);
/*** Support functions for the RISC-V 'RTOS', which provides multihart support
* without requiring multiple targets. */
/* When using the RTOS to debug, this selects the hart that is currently being
* debugged. This doesn't propagate to the hardware. */
void riscv_set_all_rtos_harts(struct target *target);
void riscv_set_rtos_hartid(struct target *target, int hartid);
/* Lists the number of harts in the system, which are assumed to be
* consecutive and start with mhartid=0. */
int riscv_count_harts(struct target *target);
/* Returns TRUE if the target has the given register on the given hart. */
bool riscv_has_register(struct target *target, int hartid, int regid);
/** Set register, updating the cache. */
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
/** Set register, updating the cache. */
int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v);
/** Get register, from the cache if it's in there. */
int riscv_get_register(struct target *target, riscv_reg_t *value,
enum gdb_regno r);
/** Get register, from the cache if it's in there. */
int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
int hartid, enum gdb_regno regid);
/* Checks the state of the current hart -- "is_halted" checks the actual
* on-device register. */
@ -329,9 +372,6 @@ int riscv_dmi_write_u64_bits(struct target *target);
/* Invalidates the register cache. */
void riscv_invalidate_register_cache(struct target *target);
/* Returns TRUE when a hart is enabled in this target. */
bool riscv_hart_enabled(struct target *target, int hartid);
int riscv_enumerate_triggers(struct target *target);
int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint);
@ -356,4 +396,7 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval);
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
riscv_bscan_tunneled_scan_context_t *ctxt);
int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
#endif

View File

@ -85,12 +85,15 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval)
if (result != ERROR_OK)
return SEMI_ERROR;
uint8_t tmp[12];
uint8_t tmp_buf[12];
/* Read the current instruction, including the bracketing */
*retval = target_read_memory(target, pc - 4, 2, 6, tmp);
if (*retval != ERROR_OK)
return SEMI_ERROR;
/* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */
for (int i = 0; i < 3; i++) {
/* Instruction memories may not support arbitrary read size. Use any size that will work. */
*retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i);
if (*retval != ERROR_OK)
return SEMI_ERROR;
}
/*
* The instructions that trigger a semihosting call,
@ -100,9 +103,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval)
* 00100073 ebreak
* 40705013 srai zero,zero,0x7
*/
uint32_t pre = target_buffer_get_u32(target, tmp);
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
uint32_t post = target_buffer_get_u32(target, tmp + 8);
uint32_t pre = target_buffer_get_u32(target, tmp_buf);
uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4);
uint32_t post = target_buffer_get_u32(target, tmp_buf + 8);
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc);
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {