/* * Support for RISC-V, debug version 0.13, which is currently (2/4/17) the * latest draft. */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" #include "log.h" #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" #include "helper/time_support.h" #include "riscv.h" #include "rtos/riscv_debug.h" #include "debug_defines.h" #include "rtos/rtos.h" #include "program.h" #include "asm.h" #include "batch.h" #define DMI_DATA1 (DMI_DATA0 + 1) static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); static riscv_addr_t riscv013_progbuf_addr(struct target *target); static riscv_addr_t riscv013_progbuf_size(struct target *target); static riscv_addr_t riscv013_data_size(struct target *target); static riscv_addr_t riscv013_data_addr(struct target *target); static void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled); static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); static void riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); static void riscv013_select_current_hart(struct target *target); static void riscv013_halt_current_hart(struct target *target); static void riscv013_resume_current_hart(struct target *target); static void riscv013_step_current_hart(struct target *target); static void riscv013_on_halt(struct target *target); static void riscv013_on_step(struct target *target); static void riscv013_on_resume(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); static void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *p); static void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *p); static void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t d); static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index); static int riscv013_execute_debug_buffer(struct target *target); static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static int riscv013_dmi_write_u64_bits(struct target *target); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); static void riscv013_reset_current_hart(struct target *target); /** * Since almost everything can be accomplish by scanning the dbus register, all * functions here assume dbus is already selected. The exception are functions * called directly by OpenOCD, which can't assume anything about what's * currently in IR. They should set IR to dbus explicitly. */ #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) #define DIM(x) (sizeof(x)/sizeof(*x)) #define CSR_DCSR_CAUSE_SWBP 1 #define CSR_DCSR_CAUSE_TRIGGER 2 #define CSR_DCSR_CAUSE_DEBUGINT 3 #define CSR_DCSR_CAUSE_STEP 4 #define CSR_DCSR_CAUSE_HALT 5 #define RISCV013_INFO(r) riscv013_info_t *r = get_info(target) /*** JTAG registers. ***/ typedef enum { DMI_OP_NOP = 0, DMI_OP_READ = 1, DMI_OP_WRITE = 2 } dmi_op_t; typedef enum { DMI_STATUS_SUCCESS = 0, DMI_STATUS_FAILED = 2, DMI_STATUS_BUSY = 3 } dmi_status_t; typedef enum { RE_OK, RE_FAIL, RE_AGAIN } riscv_error_t; typedef enum slot { SLOT0, SLOT1, SLOT_LAST, } slot_t; /*** Debug Bus registers. ***/ #define CMDERR_NONE 0 #define CMDERR_BUSY 1 #define CMDERR_NOT_SUPPORTED 2 #define CMDERR_EXCEPTION 3 #define CMDERR_HALT_RESUME 4 #define CMDERR_OTHER 7 /*** Info about the core being debugged. ***/ #define WALL_CLOCK_TIMEOUT 2 #define MAX_HWBPS 16 struct trigger { uint64_t address; uint32_t length; uint64_t mask; uint64_t value; bool read, write, execute; int unique_id; }; struct memory_cache_line { uint32_t data; bool valid; bool dirty; }; typedef struct { /* Number of address bits in the dbus register. */ unsigned abits; /* Number of abstract command data registers. */ unsigned datacount; /* Number of words in the Program Buffer. */ unsigned progsize; /* Number of Program Buffer registers. */ /* Number of words in Debug RAM. */ uint64_t misa; uint64_t tselect; bool tselect_dirty; /* The value that mstatus actually has on the target right now. This is not * the value we present to the user. That one may be stored in the * reg_cache. */ uint64_t mstatus_actual; /* Single buffer that contains all register names, instead of calling * malloc for each register. Needs to be freed when reg_list is freed. */ char *reg_names; /* Single buffer that contains all register values. */ void *reg_values; // For each physical trigger, contains -1 if the hwbp is available, or the // unique_id of the breakpoint/watchpoint that is using it. int trigger_unique_id[MAX_HWBPS]; // Number of run-test/idle cycles the target requests we do after each dbus // access. unsigned int dtmcontrol_idle; // This value is incremented every time a dbus access comes back as "busy". // It's used to determine how many run-test/idle cycles to feed the target // in between accesses. unsigned int dmi_busy_delay; // This value is increased every time we tried to execute two commands // consecutively, and the second one failed because the previous hadn't // completed yet. It's used to add extra run-test/idle cycles after // starting a command, so we don't have to waste time checking for busy to // go low. unsigned int ac_busy_delay; bool need_strict_step; // Some memoized values int progbuf_size, progbuf_addr, data_addr, data_size; } riscv013_info_t; static void decode_dmi(char *text, unsigned address, unsigned data) { 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"); } sprintf(text + strlen(text), " version=%d", get_field(data, DMI_DMSTATUS_VERSION)); break; } } static void dump_field(const struct scan_field *field) { static const char *op_string[] = {"-", "r", "w", "?"}; static const char *status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); unsigned int out_op = get_field(out, DTM_DMI_OP); unsigned int out_data = get_field(out, DTM_DMI_DATA); unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET; uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); unsigned int in_op = get_field(in, DTM_DMI_OP); unsigned int in_data = get_field(in, DTM_DMI_DATA); unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%db %s %08x @%02x -> %s %08x @%02x", field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address); char out_text[500]; char in_text[500]; decode_dmi(out_text, out_address, out_data); decode_dmi(in_text, in_address, in_data); if (in_text[0] || out_text[0]) { log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%s -> %s", out_text, in_text); } } static riscv013_info_t *get_info(const struct target *target) { riscv_info_t *info = (riscv_info_t *) target->arch_info; return (riscv013_info_t *) info->version_specific; } /*** Necessary prototypes. ***/ static int register_get(struct reg *reg); /*** Utility functions. ***/ bool supports_extension(struct target *target, char letter) { riscv013_info_t *info = get_info(target); unsigned num; if (letter >= 'a' && letter <= 'z') { num = letter - 'a'; } else if (letter >= 'A' && letter <= 'Z') { num = letter - 'A'; } else { return false; } return info->misa & (1 << num); } static void select_dmi(struct target *target) { static uint8_t ir_dmi[1] = {DTM_DMI}; struct scan_field field = { .num_bits = target->tap->ir_length, .out_value = ir_dmi, .in_value = NULL, .check_value = NULL, .check_mask = NULL }; jtag_add_ir_scan(target->tap, &field, TAP_IDLE); } static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4]; buf_set_u32(out_value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); field.num_bits = 32; field.out_value = out_value; field.in_value = in_value; jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); /* Always return to dmi. */ select_dmi(target); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); return in; } static void increase_dmi_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1; LOG_INFO("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); } static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->ac_busy_delay += info->ac_busy_delay / 10 + 1; LOG_INFO("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); } /** * exec: If this is set, assume the scan results in an execution, so more * run-test/idle cycles may be required. */ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, uint64_t *data_in, dmi_op_t op, uint16_t address_out, uint64_t data_out, bool exec) { riscv013_info_t *info = get_info(target); uint8_t in[8] = {0}; uint8_t out[8]; struct scan_field field = { .num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH, .out_value = out, .in_value = in }; assert(info->abits != 0); buf_set_u64(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); buf_set_u64(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); buf_set_u64(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); /* Assume dbus is already selected. */ jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); int idle_count = info->dmi_busy_delay; if (exec) idle_count += info->ac_busy_delay; if (idle_count) { jtag_add_runtest(idle_count, TAP_IDLE); } int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("dmi_scan failed jtag scan"); return DMI_STATUS_FAILED; } if (data_in) { *data_in = buf_get_u64(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); } if (address_in) { *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); } dump_field(&field); return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } static uint64_t dmi_read(struct target *target, uint16_t address) { select_dmi(target); uint64_t value; dmi_status_t status; uint16_t address_in; unsigned i = 0; // This first loop ensures that the read request was actually sent // to the target. Note that if for some reason this stays busy, // it is actually due to the Previous dmi_read or dmi_write. for (i = 0; i < 256; i++) { status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); } else if (status == DMI_STATUS_SUCCESS) { break; } else { LOG_ERROR("failed read from 0x%x, status=%d", address, status); break; } } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed read from 0x%x; value=0x%" PRIx64 ", status=%d", address, value, status); abort(); } // This second loop ensures that we got the read // data back. Note that NOP can result in a 'busy' result as well, but // that would be noticed on the next DMI access we do. for (i = 0; i < 256; i++) { status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); } else if (status == DMI_STATUS_SUCCESS) { break; } else { LOG_ERROR("failed read (NOP) at 0x%x, status=%d\n", address, status); break; } } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%" PRIx64 ", status=%d", address, value, status); abort(); } return value; } static void dmi_write(struct target *target, uint16_t address, uint64_t value) { select_dmi(target); dmi_status_t status = DMI_STATUS_BUSY; unsigned i = 0; // The first loop ensures that we successfully sent the write request. for (i = 0; i < 256; i++) { status = dmi_scan(target, NULL, NULL, DMI_OP_WRITE, address, value, address == DMI_COMMAND); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); } else if (status == DMI_STATUS_SUCCESS) { break; } else { LOG_ERROR("failed write to 0x%x, status=%d\n", address, status); break; } } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed write to 0x%x;, status=%d\n", address, status); abort(); } // The second loop isn't strictly necessary, but would ensure that // the write is complete/ has no non-busy errors before returning from this function. for (i = 0; i < 256; i++) { status = dmi_scan(target, NULL, NULL, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); } else if (status == DMI_STATUS_SUCCESS) { break; } else { LOG_ERROR("failed write (NOP) at 0x%x, status=%d\n", address, status); break; } } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("failed to write (NOP) 0x%" PRIx64 " to 0x%x; status=%d\n", value, address, status); abort(); } } uint32_t abstract_register_size(unsigned width) { switch (width) { case 32: return set_field(0, AC_ACCESS_REGISTER_SIZE, 2); case 64: return set_field(0, AC_ACCESS_REGISTER_SIZE, 3); break; case 128: return set_field(0, AC_ACCESS_REGISTER_SIZE, 4); break; default: LOG_ERROR("Unsupported register width: %d", width); return 0; } } static int wait_for_idle(struct target *target, uint32_t *abstractcs) { time_t start = time(NULL); while (1) { *abstractcs = dmi_read(target, DMI_ABSTRACTCS); if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) { return ERROR_OK; } if (time(NULL) - start > WALL_CLOCK_TIMEOUT) { if (get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR) != CMDERR_NONE) { const char *errors[8] = { "none", "busy", "not supported", "exception", "halt/resume", "reserved", "reserved", "other" }; LOG_ERROR("Abstract command ended in error '%s' (abstractcs=0x%x)", errors[get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR)], *abstractcs); } LOG_ERROR("Timed out waiting for busy to go low. (abstractcs=0x%x)", *abstractcs); return ERROR_FAIL; } } } static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); static int register_write_direct(struct target *target, unsigned number, uint64_t value) { struct riscv_program program; riscv_program_init(&program, target); riscv_addr_t input = riscv_program_alloc_d(&program); riscv_program_write_ram(&program, input + 4, value >> 32); riscv_program_write_ram(&program, input, value); assert(GDB_REGNO_XPR0 == 0); if (number <= GDB_REGNO_XPR31) { riscv_program_lx(&program, number, input); } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { riscv_program_fld(&program, number, input); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { enum gdb_regno temp = riscv_program_gettemp(&program); riscv_program_lx(&program, temp, input); riscv_program_csrw(&program, temp, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); abort(); } int exec_out = riscv_program_exec(&program, target); if (exec_out != ERROR_OK) { riscv013_clear_abstract_error(target); return ERROR_FAIL; } 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) { struct riscv_program program; riscv_program_init(&program, target); riscv_addr_t output = riscv_program_alloc_d(&program); riscv_program_write_ram(&program, output + 4, 0); riscv_program_write_ram(&program, output, 0); assert(GDB_REGNO_XPR0 == 0); if (number <= GDB_REGNO_XPR31) { riscv_program_sx(&program, number, output); } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { riscv_program_fsd(&program, number, output); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0); enum gdb_regno temp = riscv_program_gettemp(&program); riscv_program_csrr(&program, temp, number); riscv_program_sx(&program, temp, output); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); abort(); } int exec_out = riscv_program_exec(&program, target); if (exec_out != ERROR_OK) { riscv013_clear_abstract_error(target); return ERROR_FAIL; } *value = 0; *value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32; *value |= riscv_program_read_ram(&program, output); LOG_DEBUG("register 0x%x = 0x%" PRIx64, number, *value); return ERROR_OK; } static int maybe_read_tselect(struct target *target) { riscv013_info_t *info = get_info(target); if (info->tselect_dirty) { int result = register_read_direct(target, &info->tselect, GDB_REGNO_TSELECT); if (result != ERROR_OK) return result; info->tselect_dirty = false; } return ERROR_OK; } /*** OpenOCD target functions. ***/ static int register_get(struct reg *reg) { struct target *target = (struct target *) reg->arch_info; uint64_t value = riscv_get_register(target, reg->number); buf_set_u64(reg->value, 0, 64, value); return ERROR_OK; } static int register_write(struct target *target, unsigned int number, uint64_t value) { riscv_set_register(target, number, value); return ERROR_OK; } static int register_set(struct reg *reg, uint8_t *buf) { struct target *target = (struct target *) reg->arch_info; uint64_t value = buf_get_u64(buf, 0, riscv_xlen(target)); LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); struct reg *r = &target->reg_cache->reg_list[reg->number]; r->valid = true; memcpy(r->value, buf, (r->size + 7) / 8); return register_write(target, reg->number, value); } static struct reg_arch_type riscv_reg_arch_type = { .get = register_get, .set = register_set }; 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_init(generic_info); generic_info->get_register = &riscv013_get_register; generic_info->set_register = &riscv013_set_register; generic_info->select_current_hart = &riscv013_select_current_hart; generic_info->is_halted = &riscv013_is_halted; generic_info->halt_current_hart = &riscv013_halt_current_hart; generic_info->resume_current_hart = &riscv013_resume_current_hart; generic_info->step_current_hart = &riscv013_step_current_hart; generic_info->on_halt = &riscv013_on_halt; generic_info->on_resume = &riscv013_on_resume; generic_info->on_step = &riscv013_on_step; generic_info->halt_reason = &riscv013_halt_reason; generic_info->debug_buffer_enter = &riscv013_debug_buffer_enter; generic_info->debug_buffer_leave = &riscv013_debug_buffer_leave; generic_info->read_debug_buffer = &riscv013_read_debug_buffer; generic_info->write_debug_buffer = &riscv013_write_debug_buffer; generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; generic_info->reset_current_hart = &riscv013_reset_current_hart; generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; riscv013_info_t *info = get_info(target); info->progbuf_size = -1; info->progbuf_addr = -1; info->data_size = -1; info->data_addr = -1; info->dmi_busy_delay = 0; info->ac_busy_delay = 0; target->reg_cache = calloc(1, sizeof(*target->reg_cache)); target->reg_cache->name = "RISC-V Registers"; target->reg_cache->num_regs = GDB_REGNO_COUNT; target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); const unsigned int max_reg_name_len = 12; info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); char *reg_name = info->reg_names; info->reg_values = NULL; for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { struct reg *r = &target->reg_cache->reg_list[i]; r->number = i; r->caller_save = true; r->dirty = false; r->valid = false; r->exist = true; r->type = &riscv_reg_arch_type; r->arch_info = target; if (i <= GDB_REGNO_XPR31) { sprintf(reg_name, "x%d", i); } else if (i == GDB_REGNO_PC) { sprintf(reg_name, "pc"); } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0); } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) { sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0); } else if (i == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); } if (reg_name[0]) { r->name = reg_name; } reg_name += strlen(reg_name) + 1; assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); } #if 0 update_reg_list(target); #endif memset(info->trigger_unique_id, 0xff, sizeof(info->trigger_unique_id)); return ERROR_OK; } static void deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); riscv_info_t *info = (riscv_info_t *) target->arch_info; free(info->version_specific); info->version_specific = NULL; } static int add_trigger(struct target *target, struct trigger *trigger) { riscv013_info_t *info = get_info(target); maybe_read_tselect(target); int i; for (i = 0; i < riscv_count_triggers(target); i++) { if (info->trigger_unique_id[i] != -1) { continue; } register_write_direct(target, GDB_REGNO_TSELECT, i); uint64_t tdata1; register_read_direct(target, &tdata1, GDB_REGNO_TDATA1); int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); if (type != 2) { continue; } if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { // Trigger is already in use, presumably by user code. continue; } // address/data match trigger tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); tdata1 = set_field(tdata1, MCONTROL_ACTION, MCONTROL_ACTION_DEBUG_MODE); tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); tdata1 |= MCONTROL_M; if (info->misa & (1 << ('H' - 'A'))) tdata1 |= MCONTROL_H; if (info->misa & (1 << ('S' - 'A'))) tdata1 |= MCONTROL_S; if (info->misa & (1 << ('U' - 'A'))) tdata1 |= MCONTROL_U; if (trigger->execute) tdata1 |= MCONTROL_EXECUTE; if (trigger->read) tdata1 |= MCONTROL_LOAD; if (trigger->write) tdata1 |= MCONTROL_STORE; register_write_direct(target, GDB_REGNO_TDATA1, tdata1); uint64_t tdata1_rb; register_read_direct(target, &tdata1_rb, GDB_REGNO_TDATA1); LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (tdata1 != tdata1_rb) { LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64, i, tdata1, tdata1_rb); register_write_direct(target, GDB_REGNO_TDATA1, 0); continue; } register_write_direct(target, GDB_REGNO_TDATA2, trigger->address); LOG_DEBUG("Using resource %d for bp %d", i, trigger->unique_id); info->trigger_unique_id[i] = trigger->unique_id; break; } if (i >= riscv_count_triggers(target)) { LOG_ERROR("Couldn't find an available hardware trigger."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } return ERROR_OK; } static int remove_trigger(struct target *target, struct trigger *trigger) { riscv013_info_t *info = get_info(target); maybe_read_tselect(target); int i; for (i = 0; i < riscv_count_triggers(target); i++) { if (info->trigger_unique_id[i] == trigger->unique_id) { break; } } if (i >= riscv_count_triggers(target)) { LOG_ERROR("Couldn't find the hardware resources used by hardware " "trigger."); return ERROR_FAIL; } LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id); register_write_direct(target, GDB_REGNO_TSELECT, i); register_write_direct(target, GDB_REGNO_TDATA1, 0); info->trigger_unique_id[i] = -1; return ERROR_OK; } static void trigger_from_breakpoint(struct trigger *trigger, const struct breakpoint *breakpoint) { trigger->address = breakpoint->address; trigger->length = breakpoint->length; trigger->mask = ~0LL; trigger->read = false; trigger->write = false; trigger->execute = true; // unique_id is unique across both breakpoints and watchpoints. trigger->unique_id = breakpoint->unique_id; } static void trigger_from_watchpoint(struct trigger *trigger, const struct watchpoint *watchpoint) { trigger->address = watchpoint->address; trigger->length = watchpoint->length; trigger->mask = watchpoint->mask; trigger->value = watchpoint->value; trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); trigger->execute = false; // unique_id is unique across both breakpoints and watchpoints. trigger->unique_id = watchpoint->unique_id; } static int add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->type == BKPT_SOFT) { if (target_read_memory(target, breakpoint->address, breakpoint->length, 1, breakpoint->orig_instr) != ERROR_OK) { LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR, breakpoint->address); return ERROR_FAIL; } int retval; if (breakpoint->length == 4) { retval = target_write_u32(target, breakpoint->address, ebreak()); } else { retval = target_write_u16(target, breakpoint->address, ebreak_c()); } if (retval != ERROR_OK) { LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; } } else if (breakpoint->type == BKPT_HARD) { struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); int result = add_trigger(target, &trigger); if (result != ERROR_OK) { return result; } } else { LOG_INFO("OpenOCD only supports hardware and software breakpoints."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = true; return ERROR_OK; } static int remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->type == BKPT_SOFT) { if (target_write_memory(target, breakpoint->address, breakpoint->length, 1, breakpoint->orig_instr) != ERROR_OK) { LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; } } else if (breakpoint->type == BKPT_HARD) { struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); int result = remove_trigger(target, &trigger); if (result != ERROR_OK) { return result; } } else { LOG_INFO("OpenOCD only supports hardware and software breakpoints."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = false; return ERROR_OK; } static int add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); int result = add_trigger(target, &trigger); if (result != ERROR_OK) { return result; } watchpoint->set = true; return ERROR_OK; } static int remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); int result = remove_trigger(target, &trigger); if (result != ERROR_OK) { return result; } watchpoint->set = false; return ERROR_OK; } static int examine(struct target *target) { // Don't need to select dbus, since the first thing we do is read dtmcontrol. uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); LOG_DEBUG(" dmireset=%d", get_field(dtmcontrol, DTM_DTMCS_DMIRESET)); LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTM_DTMCS_IDLE)); LOG_DEBUG(" dmistat=%d", get_field(dtmcontrol, DTM_DTMCS_DMISTAT)); LOG_DEBUG(" abits=%d", get_field(dtmcontrol, DTM_DTMCS_ABITS)); LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTM_DTMCS_VERSION)); if (dtmcontrol == 0) { LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); return ERROR_FAIL; } if (get_field(dtmcontrol, DTM_DTMCS_VERSION) != 1) { LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", get_field(dtmcontrol, DTM_DTMCS_VERSION), dtmcontrol); return ERROR_FAIL; } riscv013_info_t *info = get_info(target); info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcontrol_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) { LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d " "(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), dmstatus); return ERROR_FAIL; } // Reset the Debug Module. dmi_write(target, DMI_DMCONTROL, 0); dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); dmcontrol = dmi_read(target, DMI_DMCONTROL); LOG_DEBUG("dmcontrol: 0x%08x", dmcontrol); LOG_DEBUG("dmstatus: 0x%08x", dmstatus); if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } if (!get_field(dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Authentication required by RISC-V core but not " "supported by OpenOCD. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) { LOG_ERROR("The hart is unavailable."); return ERROR_FAIL; } if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) { LOG_ERROR("The hart doesn't exist."); return ERROR_FAIL; } // Check that abstract data registers are accessible. uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->progsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE); /* Before doing anything else we must first enumerate the harts. */ RISCV_INFO(r); if (riscv_rtos_enabled(target)) { for (int i = 0; i < RISCV_MAX_HARTS; ++i) { riscv_set_current_hartid(target, i); uint32_t s = dmi_read(target, DMI_DMSTATUS); if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) break; r->hart_count = i + 1; } } else { r->hart_count = 1; } LOG_DEBUG("Enumerated %d harts", r->hart_count); /* Halt every hart so we can probe them. */ riscv_halt_all_harts(target); /* Find the address of the program buffer, which must be done without * knowing anything about the target. */ for (int i = 0; i < riscv_count_harts(target); ++i) { riscv_set_current_hartid(target, i); /* Without knowing anything else we can at least mess with the * program buffer. */ r->debug_buffer_size[i] = riscv013_progbuf_size(target); /* Guess this is a 32-bit system, we're probing it. */ r->xlen[i] = 32; /* First find the low 32 bits of the program buffer. This is * used to check for alignment. */ struct riscv_program program32; riscv_program_init(&program32, target); riscv_program_csrrw(&program32, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); riscv_program_insert(&program32, auipc(GDB_REGNO_S0)); riscv_program_insert(&program32, sw(GDB_REGNO_S0, GDB_REGNO_S0, -4)); riscv_program_csrrw(&program32, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); riscv_program_fence(&program32); riscv_program_exec(&program32, target); riscv_addr_t progbuf_addr = dmi_read(target, DMI_PROGBUF0) - 4; if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) != 0) { LOG_ERROR("Unable to find the address of the program buffer on hart %d", i); r->xlen[i] = -1; continue; } r->debug_buffer_addr[i] = progbuf_addr; /* Check to see if the core can execute 64 bit instructions. * In order to make this work we first need to */ int offset = (progbuf_addr % 8 == 0) ? -4 : 0; struct riscv_program program64; riscv_program_init(&program64, target); riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); riscv_program_insert(&program64, auipc(GDB_REGNO_S0)); 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); if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0) { r->debug_buffer_addr[i] = (dmi_read(target, DMI_PROGBUF0 + (8 + offset) / 4) << 32) + dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4) - 4; r->xlen[i] = 64; } /* Display this as early as possible to help people who are using * really slow simulators. */ LOG_DEBUG(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64, i, r->xlen[i], r->debug_buffer_addr[i]); if (riscv_program_gah(&program64, r->debug_buffer_addr[i])) { LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx\n", i, (long)r->debug_buffer_addr[i]); abort(); } /* Check to see if we can use the data words as an extended * program buffer or not. */ if (r->debug_buffer_addr[i] + (4 * r->debug_buffer_size[i]) == riscv013_data_addr(target)) { r->debug_buffer_size[i] += riscv013_data_size(target); LOG_DEBUG("extending the debug buffer using data words, total size %d", r->debug_buffer_size[i]); } } /* Then we check the number of triggers availiable to each hart. */ for (int i = 0; i < riscv_count_harts(target); ++i) { for (uint32_t t = 0; t < RISCV_MAX_TRIGGERS; ++t) { riscv_set_current_hartid(target, i); r->trigger_count[i] = t; register_write_direct(target, GDB_REGNO_TSELECT, t); uint64_t tselect = t+1; register_read_direct(target, &tselect, GDB_REGNO_TSELECT); if (tselect != t) break; } } /* Resumes all the harts, so the debugger can later pause them. */ riscv_resume_all_harts(target); target_set_examined(target); if (target->rtos) { riscv_update_threads(target->rtos); } // Some regression suites rely on seeing 'Examined RISC-V core' to know // when they can connect with gdb/telnet. // We will need to update those suites if we want to change that text. LOG_INFO("Examined RISC-V core; found %d harts", riscv_count_harts(target)); for (int i = 0; i < riscv_count_harts(target); ++i) { LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64 ", %d triggers", i, r->xlen[i], r->debug_buffer_addr[i], r->trigger_count[i]); } return ERROR_OK; } static int assert_reset(struct target *target) { /*FIXME -- this only works for single-hart.*/ RISCV_INFO(r); assert(r->current_hartid == 0); select_dmi(target); LOG_DEBUG("ASSERTING NDRESET"); uint32_t control = dmi_read(target, DMI_DMCONTROL); control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); if (target->reset_halt) { LOG_DEBUG("TARGET RESET HALT SET, ensuring halt is set during reset."); control = set_field(control, DMI_DMCONTROL_HALTREQ, 1); } else { LOG_DEBUG("TARGET RESET HALT NOT SET"); control = set_field(control, DMI_DMCONTROL_HALTREQ, 0); } dmi_write(target, DMI_DMCONTROL, control); return ERROR_OK; } static int deassert_reset(struct target *target) { RISCV_INFO(r); RISCV013_INFO(info); select_dmi(target); /*FIXME -- this only works for Single Hart*/ assert(r->current_hartid == 0); /*FIXME -- is there bookkeeping we need to do here*/ uint32_t control = dmi_read(target, DMI_DMCONTROL); // Clear the reset, but make sure haltreq is still set if (target->reset_halt) { control = set_field(control, DMI_DMCONTROL_HALTREQ, 1); } control = set_field(control, DMI_DMCONTROL_NDMRESET, 0); dmi_write(target, DMI_DMCONTROL, control); uint32_t status; int dmi_busy_delay = info->dmi_busy_delay; if (target->reset_halt) { LOG_DEBUG("DEASSERTING RESET, waiting for hart to be halted."); do { status = dmi_read(target, DMI_DMSTATUS); } while (get_field(status, DMI_DMSTATUS_ALLHALTED) == 0); } else { LOG_DEBUG("DEASSERTING RESET, waiting for hart to be running."); do { status = dmi_read(target, DMI_DMSTATUS); if (get_field(status, DMI_DMSTATUS_ANYHALTED) || get_field(status, DMI_DMSTATUS_ANYUNAVAIL)) { LOG_ERROR("Unexpected hart status during reset."); abort(); } } while (get_field(status, DMI_DMSTATUS_ALLRUNNING) == 0); } info->dmi_busy_delay = dmi_busy_delay; return ERROR_OK; } static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { RISCV013_INFO(info); LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); select_dmi(target); /* There was a bug in the memory system and only accesses from hart 0 actually * worked correctly. This should be obselete now. -palmer */ riscv_set_current_hartid(target, 0); /* This program uses two temporary registers. A word of data and the * associated address are stored at some location in memory. The * program loads the word from that address and then increments the * address. The debugger is expected to pull the memory word-by-word * from the chip with AUTOEXEC set in order to trigger program * execution on every word. */ uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1); struct riscv_program program; riscv_program_init(&program, target); riscv_addr_t r_data = riscv_program_alloc_w(&program); riscv_addr_t r_addr = riscv_program_alloc_x(&program); riscv_program_fence(&program); riscv_program_lx(&program, GDB_REGNO_S0, r_addr); riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 2: riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 4: riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; default: LOG_ERROR("Unsupported size: %d", size); return ERROR_FAIL; } riscv_program_sw(&program, GDB_REGNO_S1, r_data); riscv_program_sx(&program, GDB_REGNO_S0, r_addr); /* The first round through the program's execution we use the regular * program execution mechanism. */ switch (riscv_xlen(target)) { case 64: riscv_program_write_ram(&program, r_addr + 4, (((riscv_addr_t) address) - size) >> 32); case 32: riscv_program_write_ram(&program, r_addr, ((riscv_addr_t) address) - size); break; default: LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); return ERROR_FAIL; } if (riscv_program_exec(&program, target) != ERROR_OK) { uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs); riscv013_clear_abstract_error(target); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); LOG_ERROR(" exiting with ERROR_FAIL"); return ERROR_FAIL; } uint32_t value = riscv_program_read_ram(&program, r_data); LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08lx", address, (long)value); switch (size) { case 1: buffer[0] = value; break; case 2: buffer[0] = value; buffer[1] = value >> 8; break; case 4: buffer[0] = value; buffer[1] = value >> 8; buffer[2] = value >> 16; buffer[3] = value >> 24; break; default: LOG_ERROR("unsupported access size: %d", size); return ERROR_FAIL; } /* The rest of this program is designed to be fast so it reads various * DMI registers directly. */ int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4; int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4; riscv013_set_autoexec(target, d_data, 1); /* Copying memory might fail because we're going too quickly, in which * case we need to back off a bit and try again. There's two * termination conditions to this loop: a non-BUSY error message, or * the data was all copied. */ riscv_addr_t cur_addr = 0xbadbeef; riscv_addr_t fin_addr = address + (count * size); riscv_addr_t prev_addr = ((riscv_addr_t) address) - size; 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) { LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR " (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr, prev_addr); assert(prev_addr < cur_addr); prev_addr = cur_addr; riscv_addr_t start = (cur_addr - address) / size; assert (cur_addr >= address); struct riscv_batch *batch = riscv_batch_alloc( target, 32, info->dmi_busy_delay + info->ac_busy_delay); 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); reads++; if (riscv_batch_full(batch)) break; } riscv_batch_run(batch); 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); rereads++; switch (size) { case 1: t_buffer[0] = value; break; case 2: t_buffer[0] = value; t_buffer[1] = value >> 8; break; case 4: t_buffer[0] = value; t_buffer[1] = value >> 8; t_buffer[2] = value >> 16; t_buffer[3] = value >> 24; break; default: LOG_ERROR("unsupported access size: %d", size); return ERROR_FAIL; } 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); switch (get_field(abstractcs, DMI_ABSTRACTCS_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); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_OK; } static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); select_dmi(target); /* There was a bug in the memory system and only accesses from hart 0 actually * worked correctly. This should be obselete now. -palmer */ riscv_set_current_hartid(target, 0); /* This program uses two temporary registers. A word of data and the * associated address are stored at some location in memory. The * program stores the word to that address and then increments the * address. The debugger is expected to feed the memory word-by-word * into the chip with AUTOEXEC set in order to trigger program * execution on every word. */ uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1); struct riscv_program program; riscv_program_init(&program, target); riscv_addr_t r_data = riscv_program_alloc_w(&program); riscv_addr_t r_addr = riscv_program_alloc_x(&program); riscv_program_fence(&program); riscv_program_lx(&program, GDB_REGNO_S0, r_addr); riscv_program_lw(&program, GDB_REGNO_S1, r_data); switch (size) { case 1: riscv_program_sbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 2: riscv_program_shr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 4: riscv_program_swr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; default: LOG_ERROR("Unsupported size: %d", size); return ERROR_FAIL; } riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); riscv_program_sx(&program, GDB_REGNO_S0, r_addr); /* The first round through the program's execution we use the regular * program execution mechanism. */ uint32_t value; switch (size) { case 1: value = buffer[0]; break; case 2: value = buffer[0] | ((uint32_t) buffer[1] << 8); break; case 4: value = buffer[0] | ((uint32_t) buffer[1] << 8) | ((uint32_t) buffer[2] << 16) | ((uint32_t) buffer[3] << 24); break; default: LOG_ERROR("unsupported access size: %d", size); return ERROR_FAIL; } switch (riscv_xlen(target)) { case 64: riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); case 32: riscv_program_write_ram(&program, r_addr, address); break; default: LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); return ERROR_FAIL; } riscv_program_write_ram(&program, r_data, value); LOG_DEBUG("M[0x%08lx] writes 0x%08lx", (long)address, (long)value); if (riscv_program_exec(&program, target) != ERROR_OK) { uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs); riscv013_clear_abstract_error(target); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); LOG_ERROR(" exiting with ERROR_FAIL"); return ERROR_FAIL; } /* The rest of this program is designed to be fast so it reads various * DMI registers directly. */ int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4; int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4; riscv013_set_autoexec(target, d_data, 1); /* Copying memory might fail because we're going too quickly, in which * case we need to back off a bit and try again. There's two * termination conditions to this loop: a non-BUSY error message, or * the data was all copied. */ riscv_addr_t cur_addr = 0xbadbeef; riscv_addr_t fin_addr = address + (count * size); LOG_DEBUG("writing until final address 0x%016lx", fin_addr); while ((cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) { LOG_DEBUG("transferring burst starting at address 0x%016lx", cur_addr); riscv_addr_t start = (cur_addr - address) / size; assert (cur_addr > address); struct riscv_batch *batch = riscv_batch_alloc( target, 32, info->dmi_busy_delay + info->ac_busy_delay); for (riscv_addr_t i = start; i < count; ++i) { riscv_addr_t offset = size*i; riscv_addr_t t_addr = address + offset; const uint8_t *t_buffer = buffer + offset; switch (size) { case 1: value = t_buffer[0]; break; case 2: value = t_buffer[0] | ((uint32_t) t_buffer[1] << 8); break; case 4: value = t_buffer[0] | ((uint32_t) t_buffer[1] << 8) | ((uint32_t) t_buffer[2] << 16) | ((uint32_t) t_buffer[3] << 24); break; default: LOG_ERROR("unsupported access size: %d", size); return ERROR_FAIL; } LOG_DEBUG("M[0x%08lx] writes 0x%08lx", (long)t_addr, (long)value); riscv_batch_add_dmi_write( batch, riscv013_debug_buffer_register(target, r_data), value); if (riscv_batch_full(batch)) break; } riscv_batch_run(batch); 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); switch (get_field(abstractcs, DMI_ABSTRACTCS_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); riscv013_clear_abstract_error(target); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_FAIL; } } riscv013_set_autoexec(target, d_data, 0); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_OK; } static int arch_state(struct target *target) { return ERROR_OK; } struct target_type riscv013_target = { .name = "riscv", .init_target = init_target, .deinit_target = deinit_target, .examine = examine, .poll = &riscv_openocd_poll, .halt = &riscv_openocd_halt, .resume = &riscv_openocd_resume, .step = &riscv_openocd_step, .assert_reset = assert_reset, .deassert_reset = deassert_reset, .read_memory = read_memory, .write_memory = write_memory, .add_breakpoint = add_breakpoint, .remove_breakpoint = remove_breakpoint, .add_watchpoint = add_watchpoint, .remove_watchpoint = remove_watchpoint, .arch_state = arch_state, }; /*** 0.13-specific implementations of various RISC-V hepler 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); riscv_set_current_hartid(target, hid); uint64_t out; riscv013_info_t *info = get_info(target); if (rid <= GDB_REGNO_XPR31) { register_read_direct(target, &out, rid); } else if (rid == GDB_REGNO_PC) { register_read_direct(target, &out, GDB_REGNO_DPC); LOG_DEBUG("read PC from DPC: 0x%016lx", out); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; register_read_direct(target, &dcsr, CSR_DCSR); buf_set_u64((unsigned char *)&out, 0, 8, get_field(dcsr, CSR_DCSR_PRV)); } else { int result = register_read_direct(target, &out, rid); if (result != ERROR_OK) { LOG_ERROR("Unable to read register %d", rid); out = -1; } if (rid == GDB_REGNO_MSTATUS) info->mstatus_actual = out; } return out; } static void riscv013_set_register(struct target *target, int hid, int rid, uint64_t value) { LOG_DEBUG("writing register 0x%08x on hart %d", rid, hid); riscv_set_current_hartid(target, hid); if (rid <= GDB_REGNO_XPR31) { register_write_direct(target, rid, value); } else if (rid == GDB_REGNO_PC) { LOG_DEBUG("writing PC to DPC: 0x%016lx", value); register_write_direct(target, GDB_REGNO_DPC, value); uint64_t actual_value; register_read_direct(target, &actual_value, GDB_REGNO_DPC); LOG_DEBUG(" actual DPC written: 0x%016lx", actual_value); assert(value == actual_value); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; register_read_direct(target, &dcsr, CSR_DCSR); dcsr = set_field(dcsr, CSR_DCSR_PRV, value); register_write_direct(target, CSR_DCSR, dcsr); } else { register_write_direct(target, rid, value); } } static void riscv013_select_current_hart(struct target *target) { RISCV_INFO(r); uint64_t dmcontrol = dmi_read(target, DMI_DMCONTROL); dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, r->current_hartid); dmi_write(target, DMI_DMCONTROL, dmcontrol); } static void riscv013_halt_current_hart(struct target *target) { RISCV_INFO(r); LOG_DEBUG("halting hart %d", r->current_hartid); assert(!riscv_is_halted(target)); /* Issue the halt command, and then wait for the current hart to halt. */ uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) if (riscv_is_halted(target)) break; if (!riscv_is_halted(target)) { uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); dmcontrol = dmi_read(target, DMI_DMCONTROL); LOG_ERROR("unable to halt hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); LOG_ERROR(" dmstatus =0x%08x", dmstatus); abort(); } dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 0); dmi_write(target, DMI_DMCONTROL, dmcontrol); } static void riscv013_resume_current_hart(struct target *target) { return riscv013_step_or_resume_current_hart(target, false); } static void riscv013_step_current_hart(struct target *target) { return riscv013_step_or_resume_current_hart(target, true); } static void riscv013_on_resume(struct target *target) { return riscv013_on_step_or_resume(target, false); } static void riscv013_on_step(struct target *target) { return riscv013_on_step_or_resume(target, true); } static void riscv013_on_halt(struct target *target) { } static bool riscv013_is_halted(struct target *target) { uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) LOG_ERROR("hart %d is unavailiable", riscv_current_hartid(target)); if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) LOG_ERROR("hart %d doesn't exist", riscv_current_hartid(target)); return get_field(dmstatus, DMI_DMSTATUS_ALLHALTED); } static enum riscv_halt_reason riscv013_halt_reason(struct target *target) { uint64_t dcsr = riscv_get_register(target, GDB_REGNO_DCSR); switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: case CSR_DCSR_CAUSE_TRIGGER: return RISCV_HALT_BREAKPOINT; case CSR_DCSR_CAUSE_STEP: return RISCV_HALT_SINGLESTEP; case CSR_DCSR_CAUSE_DEBUGINT: case CSR_DCSR_CAUSE_HALT: return RISCV_HALT_INTERRUPT; } LOG_ERROR("Unknown DCSR cause field: %x", (int)get_field(dcsr, CSR_DCSR_CAUSE)); LOG_ERROR(" dcsr=0x%016lx", (long)dcsr); abort(); } void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *program) { } void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *program) { } void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { if (index >= riscv013_progbuf_size(target)) return dmi_write(target, DMI_DATA0 + index - riscv013_progbuf_size(target), data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { if (index >= riscv013_progbuf_size(target)) return dmi_read(target, DMI_DATA0 + index - riscv013_progbuf_size(target)); return dmi_read(target, DMI_PROGBUF0 + 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; } void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_WRITE); buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, d); buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_READ); buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } void riscv013_fill_dmi_nop_u64(struct target *target, char *buf) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, 0); } int riscv013_dmi_write_u64_bits(struct target *target) { RISCV013_INFO(info); return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } void riscv013_reset_current_hart(struct target *target) { select_dmi(target); uint32_t control = dmi_read(target, DMI_DMCONTROL); control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); control = set_field(control, DMI_DMCONTROL_HALTREQ, 1); dmi_write(target, DMI_DMCONTROL, control); control = set_field(control, DMI_DMCONTROL_NDMRESET, 0); dmi_write(target, DMI_DMCONTROL, control); while (get_field(dmi_read(target, DMI_DMSTATUS), DMI_DMSTATUS_ALLHALTED) == 0); control = set_field(control, DMI_DMCONTROL_HALTREQ, 0); dmi_write(target, DMI_DMCONTROL, control); } /* Helper Functions. */ static void riscv013_on_step_or_resume(struct target *target, bool step) { struct riscv_program program; riscv_program_init(&program, target); 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. */ uint64_t dcsr = riscv_get_register(target, GDB_REGNO_DCSR); dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKH, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } static void riscv013_step_or_resume_current_hart(struct target *target, bool step) { RISCV_INFO(r); LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); assert(riscv_is_halted(target)); struct riscv_program program; riscv_program_init(&program, target); riscv_program_fence_i(&program); if (riscv_program_exec(&program, target) != ERROR_OK) abort(); /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) { usleep(10); uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); if (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0) continue; if (step && get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0) continue; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0); dmi_write(target, DMI_DMCONTROL, dmcontrol); return; } uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); dmcontrol = dmi_read(target, DMI_DMCONTROL); LOG_ERROR("unable to resume hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); LOG_ERROR(" dmstatus =0x%08x", dmstatus); if (step) { LOG_ERROR(" was stepping, halting"); riscv013_halt_current_hart(target); return; } abort(); } riscv_addr_t riscv013_progbuf_addr(struct target *target) { RISCV013_INFO(info); assert(info->progbuf_addr != -1); return info->progbuf_addr; } riscv_addr_t riscv013_progbuf_size(struct target *target) { RISCV013_INFO(info); if (info->progbuf_size == -1) { uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); info->progbuf_size = get_field(acs, DMI_ABSTRACTCS_PROGSIZE); } return info->progbuf_size; } riscv_addr_t riscv013_data_size(struct target *target) { RISCV013_INFO(info); if (info->data_size == -1) { uint32_t acs = dmi_read(target, DMI_HARTINFO); info->data_size = get_field(acs, DMI_HARTINFO_DATASIZE); } return info->data_size; } riscv_addr_t riscv013_data_addr(struct target *target) { RISCV013_INFO(info); if (info->data_addr == -1) { uint32_t acs = dmi_read(target, DMI_HARTINFO); info->data_addr = get_field(acs, DMI_HARTINFO_DATAACCESS) ? get_field(acs, DMI_HARTINFO_DATAADDR) : 0; } return info->data_addr; } void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) { if (index >= riscv013_progbuf_size(target)) { LOG_DEBUG("setting bit %d in AUTOEXECDATA to %d", index, enabled); uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA); aa_aed &= ~(1 << (index - riscv013_progbuf_size(target))); aa_aed |= (enabled << (index - riscv013_progbuf_size(target))); aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA, aa_aed); dmi_write(target, DMI_ABSTRACTAUTO, aa); } else { LOG_DEBUG("setting bit %d in AUTOEXECPROGBUF to %d", index, enabled); uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); aa_aed &= ~(1 << index); aa_aed |= (enabled << index); aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, aa_aed); dmi_write(target, DMI_ABSTRACTAUTO, aa); } } int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) { if (addr >= riscv013_data_addr(target)) return DMI_DATA0 + (addr - riscv013_data_addr(target)) / 4; else return DMI_PROGBUF0 + (addr - riscv013_progbuf_addr(target)) / 4; } void riscv013_clear_abstract_error(struct target *target) { uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); dmi_write(target, DMI_ABSTRACTCS, acs); }